et_gds_design_system 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e6cf13d18b9af22fef35047f273d4f05c7854c48f1b53926cf457748a88cb9b7
4
+ data.tar.gz: e5601ee34dff079c3eb612fece77676ee7b75858c026bd0660cb223ed387d5e0
5
+ SHA512:
6
+ metadata.gz: 750b75c653b49b7930e102dd165ab28fda0734eef4dd8fcbbfcef3f30ac85780ba3f05bf23b73370cfde2f6826389f3685b3ac2497f4982d074a64b575477a86
7
+ data.tar.gz: a1296d508552f27b449ef4dd508c238340c9c16cd969a61ac5a2019a0b887f4ee70f0d3d93f39b96f3f31bb5caa4119d31d093bc09a8272d9fb234cbc3743f94
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Gary Taylor
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # ET GDS Design System
2
+ This gem integrates the govuk-frontend npm modules into a rails
3
+ application that is using webpacker.
4
+
5
+ ## Usage
6
+
7
+ The example application in test/dummy provides many examples
8
+ on how to use this gem. It is named the 'Kitchen Sink' as it has everything
9
+ but the kitchen sink !
10
+
11
+ Please view the source code in there for more examples, but here
12
+ is one for a form component
13
+
14
+ ```ruby
15
+ <%= form_for @kitchen_sink, builder: EtGdsDesignSystem.form_builder_class do |f| %>
16
+ <h2>Text Field</h2>
17
+ <div>
18
+ <%= f.govuk_text_field :text_field_value, label: { text: 'Text field value label' }, hint_text: 'Hint text' %>
19
+ </div>
20
+
21
+
22
+ <% end %>
23
+ ```
24
+
25
+ ## Installation
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'et_gds_design_system', git: 'git@github.com:hmcts/et_gds_design_system.git', tag: 'v0.1.0'
30
+ ```
31
+
32
+ And then execute:
33
+ ```bash
34
+ $ bundle exec rails g et_gds_design_system:install
35
+ ```
36
+
37
+ You might want to review what it has done - which will work if you
38
+ have an application pack in app/javascript/packs/application.js
39
+
40
+ Also, you may want to consider changing 'extract_css' to true in
41
+ your config/webpacker.yml so that your css works when
42
+ using browsers without javascript.
43
+
44
+ ## Contributing
45
+
46
+ Whilst this gem is wrapping the work done by others in the [gov-uk-frontend](https://www.npmjs.com/package/govuk-frontend) npm
47
+ module, it is important to always think that it may not always
48
+ use that, so wrap things accordingly.
49
+
50
+ Also, the gem may choose to extend functionality provided by govuk-frontend or event
51
+ modify functionality, so do not expect the user of this gem to know
52
+ anything about govuk-frontend.
53
+
54
+ When documenting, you can refer to govuk-frontend for various items but
55
+ because this gem can override things, be careful not to send the
56
+ user on a wild goose chase when linking to this documentation if the gem
57
+ has extended or modified functionality.
58
+
59
+ For detailed documentation, see [docs/development.md](docs/development.md)
60
+
61
+ ## License
62
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+ require_relative 'test/dummy/config/application'
9
+ load 'rails/tasks/framework.rake'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'EtGdsDesignSystem'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.md')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ load 'rails/tasks/statistics.rake'
20
+
21
+ require 'bundler/gem_tasks'
22
+
23
+ require 'rake/testtask'
24
+
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.libs << 'test'
27
+ t.pattern = 'test/**/*_test.rb'
28
+ t.verbose = false
29
+ end
30
+
31
+ task default: :test
@@ -0,0 +1,10 @@
1
+ module EtGdsDesignSystem
2
+ module FileDropzoneHelper
3
+ def hidden_field_for(key, form_builder:, attribute_name:, builder: )
4
+ attribute_value = builder.object.send(attribute_name)
5
+ options = { data: { submit_key: key.to_s } }
6
+ options[:value] = attribute_value[key.to_s] unless attribute_value.nil? || attribute_value[key.to_s].nil?
7
+ form_builder.hidden_field(key, options)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ export default `
2
+ <div class="dz-preview dz-file-previewzzzzzz">
3
+ <div>
4
+ <div class="govuk-body-s">
5
+ <span>File selected:</span>
6
+ <span data-dz-name></span>
7
+ </div>
8
+ </div>
9
+ <div class="dz-progress">
10
+ <span class="dz-upload" data-dz-uploadprogress></span>
11
+ </div>
12
+ <div class="dz-error-message"><span data-dz-errormessage></span></div>
13
+ <div class="dz-success-mark">
14
+ <svg
15
+ width="54"
16
+ height="54"
17
+ viewBox="0 0 54 54"
18
+ fill="white"
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ >
21
+ <path
22
+ d="M10.2071 29.7929L14.2929 25.7071C14.6834 25.3166 15.3166 25.3166 15.7071 25.7071L21.2929 31.2929C21.6834 31.6834 22.3166 31.6834 22.7071 31.2929L38.2929 15.7071C38.6834 15.3166 39.3166 15.3166 39.7071 15.7071L43.7929 19.7929C44.1834 20.1834 44.1834 20.8166 43.7929 21.2071L22.7071 42.2929C22.3166 42.6834 21.6834 42.6834 21.2929 42.2929L10.2071 31.2071C9.81658 30.8166 9.81658 30.1834 10.2071 29.7929Z"
23
+ />
24
+ </svg>
25
+ </div>
26
+ <div class="dz-error-mark">
27
+ <svg
28
+ width="54"
29
+ height="54"
30
+ viewBox="0 0 54 54"
31
+ fill="white"
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ >
34
+ <path
35
+ d="M26.2929 20.2929L19.2071 13.2071C18.8166 12.8166 18.1834 12.8166 17.7929 13.2071L13.2071 17.7929C12.8166 18.1834 12.8166 18.8166 13.2071 19.2071L20.2929 26.2929C20.6834 26.6834 20.6834 27.3166 20.2929 27.7071L13.2071 34.7929C12.8166 35.1834 12.8166 35.8166 13.2071 36.2071L17.7929 40.7929C18.1834 41.1834 18.8166 41.1834 19.2071 40.7929L26.2929 33.7071C26.6834 33.3166 27.3166 33.3166 27.7071 33.7071L34.7929 40.7929C35.1834 41.1834 35.8166 41.1834 36.2071 40.7929L40.7929 36.2071C41.1834 35.8166 41.1834 35.1834 40.7929 34.7929L33.7071 27.7071C33.3166 27.3166 33.3166 26.6834 33.7071 26.2929L40.7929 19.2071C41.1834 18.8166 41.1834 18.1834 40.7929 17.7929L36.2071 13.2071C35.8166 12.8166 35.1834 12.8166 34.7929 13.2071L27.7071 20.2929C27.3166 20.6834 26.6834 20.6834 26.2929 20.2929Z"
36
+ />
37
+ </svg>
38
+ </div>
39
+ <button class="govuk-button govuk-button--secondary" data-module="govuk-button" data-dz-remove>
40
+ Remove File
41
+ </button>
42
+ </div>
43
+ `
@@ -0,0 +1,11 @@
1
+ .dropzone.gds-dropzone-uploader {
2
+ border: none;
3
+ padding: 0px;
4
+ .dz-message {
5
+ text-align: left;
6
+ margin: 0px;
7
+ }
8
+ }
9
+ .gds-dropzone-uploader-preview-template {
10
+ display: none;
11
+ }
@@ -0,0 +1,196 @@
1
+ import Dropzone from "dropzone";
2
+ import axios from "axios";
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ import SparkMD5 from 'spark-md5';
5
+ import previewTemplate from "./DropzoneUploader/preview-template.html";
6
+ Dropzone.autoDiscover = false
7
+
8
+ let uploadKey, dropzoneUploadForm;
9
+
10
+ function setUploadUrl(url) {
11
+ dropzoneUploadForm.options.url = url;
12
+ }
13
+
14
+ function buildUpload(cb) {
15
+ axios.post(
16
+ "/api/v2/build_blob",
17
+ {
18
+ uuid: uuidv4(),
19
+ command: "BuildBlob",
20
+ async: false,
21
+ data: {
22
+ preventEmptyData: true
23
+ }
24
+ },
25
+ {
26
+ responseType: 'json',
27
+ headers: {
28
+ 'Accept': 'application/json'
29
+ }
30
+ }
31
+ )
32
+ .then((response) => {
33
+ cb.apply(this, [response.data]);
34
+ })
35
+ .catch(onGetPresignedError)
36
+ }
37
+
38
+ function onGetPresignedError(error) {
39
+ /* TODO: RST-1220:
40
+ Anticipate and handle errors:
41
+ - Network issue to API (no response)
42
+ - Network issue to/from Azure/S3 (API responds with bad data)
43
+ */
44
+ }
45
+
46
+ function hideButton() {
47
+ document.querySelector("*[data-auto-hide]").style.display = 'none';
48
+ }
49
+
50
+ function showButton() {
51
+ document.querySelector("*[data-auto-hide]").style.display = '';
52
+ }
53
+
54
+
55
+ function setupAzure(file, presignedData, done) {
56
+ dropzoneUploadForm.options.method = 'put';
57
+ dropzoneUploadForm.options.headers = {"x-ms-blob-type": "BlockBlob"};
58
+ getFileHash(file, function (hash) {
59
+ dropzoneUploadForm.options.headers["Content-MD5"] = hash;
60
+ uploadKey = presignedData.data.fields.key;
61
+ setUploadUrl(presignedData.data.url);
62
+ hideButton();
63
+ done();
64
+ })
65
+ }
66
+
67
+ function getFileHash(file, headerCallback) {
68
+ let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
69
+ chunkSize = 2097152, // Read in chunks of 2MB
70
+ chunks = Math.ceil(file.size / chunkSize),
71
+ currentChunk = 0,
72
+ spark = new SparkMD5.ArrayBuffer(),
73
+ fileReader = new FileReader();
74
+
75
+ fileReader.onload = function (e) {
76
+ spark.append(e.target.result); // Append array buffer
77
+ currentChunk++;
78
+
79
+ if (currentChunk < chunks) {
80
+ loadNext();
81
+ } else {
82
+ const hash = btoa(spark.end(true));
83
+ headerCallback(hash);
84
+ }
85
+ };
86
+
87
+ fileReader.onerror = function () {
88
+ console.warn('oops, something went wrong.');
89
+ };
90
+
91
+ function loadNext() {
92
+ let start = currentChunk * chunkSize,
93
+ end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
94
+
95
+ fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
96
+ }
97
+
98
+ loadNext();
99
+ }
100
+
101
+ /**
102
+ *
103
+ * @param node
104
+ * @param type - The content type - for ET3 was 'application/rtf'
105
+ * @param acceptedFiles - The accepted files - for ET3 was ".rtf"
106
+ * @param removeFileButtonText - Self explanatory
107
+ * @param attributeName - The attribute name from rails
108
+ * @returns {}
109
+ */
110
+ const initDropzone = (node, type, acceptedFiles, attributeName) => {
111
+ let provider;
112
+ const extractPreviewContent = () => {
113
+ const templateContainer = node.querySelector('*[data-gds-dropzone-uploader-preview-template]')
114
+ templateContainer.parentElement.removeChild(templateContainer)
115
+ return templateContainer.innerHTML
116
+ }
117
+
118
+ const DROPZONE_OPTIONS = {
119
+ url: '/api/v2/create_blob',
120
+ init: function () {
121
+ this.on("maxfilesexceeded", function (file) {
122
+ // TODO: RST-1220 - Error Handling:
123
+ // Build a proper warning system for "too many files" warning.
124
+ alert("Too many files")
125
+ });
126
+ this.on("removedfile", function () {
127
+ node.querySelectorAll("*[data-submit-key]").forEach((inputEl) => inputEl.removeAttribute('value'))
128
+ });
129
+ this.on('sending', (file, xhr) => {
130
+ // Source: https://github.com/enyo/dropzone/issues/590#issuecomment-51498225
131
+ if (provider === 'azure') {
132
+ const send = xhr.send;
133
+ xhr.send = function () {
134
+ send.call(xhr, file);
135
+ xhr.send = send;
136
+ };
137
+ }
138
+ });
139
+ this.on('success', (file, decodedResponse, event) => {
140
+ uploadKey = decodedResponse.data.key
141
+ node.querySelector("*[data-submit-key=path]").setAttribute('value', uploadKey)
142
+ node.querySelector("*[data-submit-key=filename]").setAttribute('value', file.name)
143
+ node.querySelector("*[data-submit-key=content_type]").setAttribute('value', file.type)
144
+ showButton();
145
+ })
146
+
147
+ let filenameElement = node.querySelector("*[data-submit-key=filename]");
148
+ let filenameValue = filenameElement.getAttribute('value');
149
+ if (filenameValue) {
150
+ let existingFile = {name: filenameValue, type: type};
151
+ this.options.addedfile.call(this, existingFile);
152
+ existingFile.previewElement.classList.add('dz-success');
153
+ existingFile.previewElement.classList.add('dz-complete');
154
+ }
155
+ },
156
+ // Only one file goes to the bucket via the URL
157
+ parallelUploads: 1,
158
+ uploadMultiple: false,
159
+ // Set acceptance criteria, one .rtf file
160
+ maxFiles: 1,
161
+ acceptedFiles: acceptedFiles,
162
+ clickable: '*[data-gds-dropzone-upload-button]',
163
+ previewTemplate: extractPreviewContent(),
164
+ // Use POST by default for AWS
165
+ // TODO: RST-1676 Default this to 'put' and remove the assignment within the buildUpload if statement
166
+ method: "post",
167
+ // Add a link to remove files that were erroneously uploaded
168
+ addRemoveLinks: false,
169
+ canceled: function (file) {
170
+ showButton()
171
+ node.querySelectorAll("*[data-submit-key]").forEach((inputEl) => inputEl.setAttribute('value', null))
172
+ }
173
+ };
174
+
175
+ dropzoneUploadForm = new Dropzone(node, DROPZONE_OPTIONS)
176
+ return dropzoneUploadForm
177
+ }
178
+
179
+ /**
180
+ * @param uploadKeyId
181
+ * @param fileNameId
182
+ * @param type - The content type - for ET3 was 'application/rtf'
183
+ * @param acceptedFiles - The accepted files - for ET3 was ".rtf"
184
+ */
185
+ const DropzoneUploader = {
186
+ init: () => {
187
+ const nodes = Array.from(document.querySelectorAll('[data-module="et-gds-design-system-dropzone-uploader"]'));
188
+ nodes.forEach((node) => {
189
+ const type = node.getAttribute('data-type')
190
+ const acceptedFiles = node.getAttribute('data-accepted-files')
191
+ const attributeName = node.getAttribute('data-attribute-name')
192
+ initDropzone(node, type, acceptedFiles, attributeName);
193
+ })
194
+ }
195
+ }
196
+ export default DropzoneUploader;
@@ -0,0 +1,62 @@
1
+ const RevealOnRadioButton = {
2
+ init: function RevealOnRadioButton() {
3
+ const nodes = Array.from(document.querySelectorAll('[data-module="et-gds-design-system-reveal-on-radio-button"]'));
4
+ document.addEventListener('change', function(e) {
5
+ const nodesToChange = nodes.filter((node) => {
6
+ return e.target.matches(node.attributes['data-reveal-on-selector'].value);
7
+ });
8
+ if (nodesToChange.length == 0) {
9
+ return;
10
+ }
11
+
12
+ nodesToChange.forEach((node) => {
13
+ const value = JSON.parse(node.attributes['data-reveal-on-value'].value);
14
+ if((e.target.value === value || (Array.isArray(value) && value.indexOf(e.target.value) >= 0)) && e.target.checked) {
15
+ showNode(node);
16
+ } else {
17
+ hideNode(node);
18
+ }
19
+ });
20
+ });
21
+ setInitialStates(nodes);
22
+ }
23
+ }
24
+
25
+ /**
26
+ *
27
+ * Hides or shows (reveals) an element based on a radio button group
28
+ * @param node {Element} The element to hide or show
29
+ * @param selector {String} A css selector to identify the radio button group
30
+ * @param value {String} The value that the radio button group must be set to in order to show the element
31
+ */
32
+ export default RevealOnRadioButton
33
+ function showNode(node) {
34
+ node.style.display = 'block';
35
+ }
36
+
37
+ function hideNode(node) {
38
+ node.style.display = 'none';
39
+ }
40
+
41
+ function setInitialStates(nodes) {
42
+ nodes.forEach((node) => {
43
+ const selector = node.attributes['data-reveal-on-selector'].value;
44
+ const value = JSON.parse(node.attributes['data-reveal-on-value'].value);
45
+ if(isCorrectValue(node, selector, value)) {
46
+ showNode(node);
47
+ } else {
48
+ hideNode(node);
49
+ }
50
+ });
51
+ }
52
+
53
+ function isCorrectValue(node, selector, value) {
54
+ let isChecked = false;
55
+ document.querySelectorAll(selector).forEach(function(radioButton) {
56
+ if((radioButton.value === value || value.includes(radioButton.value)) && radioButton.checked) {
57
+ isChecked = true
58
+ }
59
+
60
+ });
61
+ return isChecked;
62
+ }
@@ -0,0 +1,8 @@
1
+ import RevealOnRadioButton from './components/RevealOnRadioButton'
2
+ import DropzoneUploader from "./components/DropzoneUploader";
3
+ const Components = {
4
+ RevealOnRadioButton: RevealOnRadioButton,
5
+ DropzoneUploader: DropzoneUploader
6
+ };
7
+ import './components/DropzoneUploader/stylesheet.scss'
8
+ export default Components;
@@ -0,0 +1,11 @@
1
+ module EtGdsDesignSystem
2
+ class AzureFile < ActiveModel::Type::Value
3
+ private
4
+
5
+ def cast_value(value)
6
+ return nil unless value.is_a?(Hash) && value['filename'].present? && value['path'].present? && value['content_type'].present?
7
+
8
+ value
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module EtGdsDesignSystem
2
+ class DateWithoutDayType < ActiveRecord::Type::Date
3
+
4
+ private
5
+
6
+ def fallback_string_to_date(string)
7
+ new_date(*::Date._parse(string, false).values_at(:year, :mon), 1)
8
+ end
9
+
10
+ def value_from_multiparameter_assignment(value)
11
+ super(value.merge(3 => 1))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,63 @@
1
+ <div class="dropzone gds-dropzone-uploader"
2
+ id="<%= id %>"
3
+ data-module="et-gds-design-system-dropzone-uploader"
4
+ data-attribute-name="<%= attribute_name %>"
5
+ data-type="<%= type %>"
6
+ data-accepted-files="<%= accepted_files.join(',') %>"
7
+ >
8
+ <div class="dz-message">
9
+ <div>
10
+ <button type="button" class="govuk-button govuk-button--secondary" data-auto-hide data-gds-dropzone-upload-button>
11
+ <%= button_text %>
12
+ </button>
13
+ </div>
14
+ </div>
15
+ <%= builder.fields_for(attribute_name) do |f| %>
16
+ <%= hidden_field_for(:path, form_builder: f, builder: builder, attribute_name: attribute_name) %>
17
+ <%= hidden_field_for(:filename, form_builder: f, builder: builder, attribute_name: attribute_name) %>
18
+ <%= hidden_field_for(:content_type, form_builder: f, builder: builder, attribute_name: attribute_name) %>
19
+ <% end %>
20
+ <div class="gds-dropzone-uploader-preview-template" style="display: none;" data-gds-dropzone-uploader-preview-template>
21
+ <div class="dz-preview">
22
+ <div>
23
+ <div class="govuk-body-s">
24
+ <span><%= file_selected_text %></span>
25
+ <span data-dz-name></span>
26
+ </div>
27
+ </div>
28
+ <div class="dz-progress">
29
+ <span class="dz-upload" data-dz-uploadprogress></span>
30
+ </div>
31
+ <div class="dz-error-message"><span data-dz-errormessage></span></div>
32
+ <div class="dz-success-mark">
33
+ <svg
34
+ width="54"
35
+ height="54"
36
+ viewBox="0 0 54 54"
37
+ fill="white"
38
+ xmlns="http://www.w3.org/2000/svg"
39
+ >
40
+ <path
41
+ d="M10.2071 29.7929L14.2929 25.7071C14.6834 25.3166 15.3166 25.3166 15.7071 25.7071L21.2929 31.2929C21.6834 31.6834 22.3166 31.6834 22.7071 31.2929L38.2929 15.7071C38.6834 15.3166 39.3166 15.3166 39.7071 15.7071L43.7929 19.7929C44.1834 20.1834 44.1834 20.8166 43.7929 21.2071L22.7071 42.2929C22.3166 42.6834 21.6834 42.6834 21.2929 42.2929L10.2071 31.2071C9.81658 30.8166 9.81658 30.1834 10.2071 29.7929Z"
42
+ />
43
+ </svg>
44
+ </div>
45
+ <div class="dz-error-mark">
46
+ <svg
47
+ width="54"
48
+ height="54"
49
+ viewBox="0 0 54 54"
50
+ fill="white"
51
+ xmlns="http://www.w3.org/2000/svg"
52
+ >
53
+ <path
54
+ d="M26.2929 20.2929L19.2071 13.2071C18.8166 12.8166 18.1834 12.8166 17.7929 13.2071L13.2071 17.7929C12.8166 18.1834 12.8166 18.8166 13.2071 19.2071L20.2929 26.2929C20.6834 26.6834 20.6834 27.3166 20.2929 27.7071L13.2071 34.7929C12.8166 35.1834 12.8166 35.8166 13.2071 36.2071L17.7929 40.7929C18.1834 41.1834 18.8166 41.1834 19.2071 40.7929L26.2929 33.7071C26.6834 33.3166 27.3166 33.3166 27.7071 33.7071L34.7929 40.7929C35.1834 41.1834 35.8166 41.1834 36.2071 40.7929L40.7929 36.2071C41.1834 35.8166 41.1834 35.1834 40.7929 34.7929L33.7071 27.7071C33.3166 27.3166 33.3166 26.6834 33.7071 26.2929L40.7929 19.2071C41.1834 18.8166 41.1834 18.1834 40.7929 17.7929L36.2071 13.2071C35.8166 12.8166 35.1834 12.8166 34.7929 13.2071L27.7071 20.2929C27.3166 20.6834 26.6834 20.6834 26.2929 20.2929Z"
55
+ />
56
+ </svg>
57
+ </div>
58
+ <button class="govuk-button govuk-button--secondary" data-module="govuk-button" data-dz-remove>
59
+ <%= remove_file_button_text %>
60
+ </button>
61
+ </div>
62
+ </div>
63
+ </div>
@@ -0,0 +1,4 @@
1
+ Rails.application.config.to_prepare do
2
+ ActiveRecord::Type.register(:date_without_day, EtGdsDesignSystem::DateWithoutDayType)
3
+ ActiveRecord::Type.register(:gds_azure_file, EtGdsDesignSystem::AzureFile)
4
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Rails.application.routes.draw do
2
+ mount EtGdsDesignSystem::ApiProxy.new(backend: "#{Rails.application.config.et_gds_design_system.api_url}", streaming: false), at: "/api/v2/create_blob"
3
+ mount EtGdsDesignSystem::ApiProxy.new(backend: "#{Rails.application.config.et_gds_design_system.api_url}", streaming: false), at: "/api/v2/blobs/:signed_id/*filename"
4
+ end
@@ -0,0 +1,25 @@
1
+ require 'rack-proxy'
2
+
3
+ module EtGdsDesignSystem
4
+ class ApiProxy < Rack::Proxy
5
+ def rewrite_env(env)
6
+ env.merge 'REQUEST_URI' => correct_host(env['REQUEST_URI']),
7
+ 'HTTP_HOST' => "#{et_api_uri.host}:#{et_api_uri.port}",
8
+ 'PATH_INFO' => ''
9
+ end
10
+
11
+ private
12
+
13
+ def correct_host(url)
14
+ uri = URI.parse(url)
15
+ uri.scheme = et_api_uri.scheme
16
+ uri.host = et_api_uri.host
17
+ uri.port = et_api_uri.port
18
+ uri.to_s
19
+ end
20
+
21
+ def et_api_uri
22
+ @et_api_uri ||= URI.parse(Rails.application.config.et_gds_design_system.api_url)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module EtGdsDesignSystem
2
+ module Elements
3
+ class Date < ::GOVUKDesignSystemFormBuilder::Elements::Date
4
+ private
5
+
6
+ def value(segment)
7
+ attribute = @builder.object.try(@attribute_name)
8
+ attribute ||= @builder.object.read_attribute_before_type_cast(@attribute_name)
9
+
10
+ return unless attribute
11
+
12
+ if attribute.respond_to?(segment)
13
+ attribute.send(segment)
14
+ elsif attribute.respond_to?(:fetch)
15
+ attribute.fetch(MULTIPARAMETER_KEY[segment]) do
16
+ warn("No key '#{segment}' found in MULTIPARAMETER_KEY hash. Expected to find #{MULTIPARAMETER_KEY.values}")
17
+
18
+ nil
19
+ end
20
+ else
21
+ fail(ArgumentError, "invalid Date-like object: must be a Date, Time, DateTime or Hash in MULTIPARAMETER_KEY format")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ require 'govuk_design_system_formbuilder/base'
2
+ require 'govuk_design_system_formbuilder/refinements/prefixable_array'
3
+ require 'govuk_design_system_formbuilder/traits/error'
4
+ require 'govuk_design_system_formbuilder/traits/hint'
5
+ require 'govuk_design_system_formbuilder/traits/label'
6
+ require 'govuk_design_system_formbuilder/traits/supplemental'
7
+ require 'govuk_design_system_formbuilder/traits/html_attributes'
8
+ require 'govuk_design_system_formbuilder/containers/form_group'
9
+ module EtGdsDesignSystem
10
+ module Elements
11
+ class FileDropzone < ::GOVUKDesignSystemFormBuilder::Base
12
+ using ::GOVUKDesignSystemFormBuilder::PrefixableArray
13
+
14
+ include ::GOVUKDesignSystemFormBuilder::Traits::Error
15
+ include ::GOVUKDesignSystemFormBuilder::Traits::Hint
16
+ include ::GOVUKDesignSystemFormBuilder::Traits::Label
17
+ include ::GOVUKDesignSystemFormBuilder::Traits::Supplemental
18
+ include ::GOVUKDesignSystemFormBuilder::Traits::HTMLAttributes
19
+
20
+ def initialize(builder, object_name, attribute_name, hint:, label:, button_text: nil, remove_file_button_text: nil, file_selected_text: nil, caption:, form_group:, accepted_files: nil, type: nil, template:, **kwargs, &block)
21
+ super(builder, object_name, attribute_name, &block)
22
+
23
+ @label = label
24
+ @caption = caption
25
+ @hint = hint
26
+ @html_attributes = kwargs
27
+ @form_group = form_group
28
+ @accepted_files = accepted_files
29
+ @button_text = button_text
30
+ @remove_file_button_text = remove_file_button_text
31
+ @file_selected_text = file_selected_text
32
+ @template = template
33
+ end
34
+
35
+ def html
36
+ ::GOVUKDesignSystemFormBuilder::Containers::FormGroup.new(*bound, **@form_group).html do
37
+ safe_join([label_element, supplemental_content, hint_element, error_element, file])
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :template
44
+
45
+ def file
46
+ template.render partial: 'et_gds_design_system/elements/file_dropzone/template',
47
+ locals: {
48
+ id: field_id(link_errors: true),
49
+ attribute_name: @attribute_name,
50
+ remove_file_button_text: @remove_file_button_text,
51
+ button_text: @button_text,
52
+ file_selected_text: @file_selected_text,
53
+ type: @type,
54
+ accepted_files: @accepted_files,
55
+ builder: @builder
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,7 @@
1
+ require 'et_gds_design_system/api_proxy'
2
+ module EtGdsDesignSystem
3
+ class Engine < ::Rails::Engine
4
+ config.et_gds_design_system = ::Rails::Application::Configuration::Custom.new
5
+ config.et_gds_design_system.api_url = 'http://api.et.127.0.0.1.nip.io:3100/api'
6
+ end
7
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "govuk_design_system_formbuilder"
4
+ require "et_gds_design_system/elements/date"
5
+ require "et_gds_design_system/elements/file_dropzone"
6
+ module EtGdsDesignSystem
7
+ module Form
8
+ class Builder < SimpleDelegator
9
+ LABEL_DEFAULTS = { size: 's' }.freeze
10
+ FIELDSET_LABEL_DEFAULTS = { size: 'm' }
11
+ CHECK_BOX_LABEL_DEFAULTS = { size: nil }
12
+ HINT_DEFAULTS = {}.freeze
13
+ OPTIONAL_I18N_KEY = 'shared.optional'
14
+
15
+ def initialize(object_name, object, template, options)
16
+ @template = template
17
+ super ::GOVUKDesignSystemFormBuilder::FormBuilder.new(object_name, object, template, options)
18
+ end
19
+
20
+ def govuk_date_field(*args, label:, **kw_args)
21
+ super(*args, legend: label, **kw_args)
22
+ end
23
+ deprecate govuk_date_field: 'govuk_date_field is deprecated - please use date_field instead and read the documentation as it makes your code simpler'
24
+
25
+ def date_field(attribute, *args, label: true, hint: true, optional: false, caption: {}, date_of_birth: false, omit_day: false, form_group: {}, wildcards: false, **kw_args, &block)
26
+ Elements::Date.new(self, object_name, attribute, hint: normalize_hint(attribute, hint), legend: normalize_label(attribute, label, optional), caption: caption, date_of_birth: date_of_birth, omit_day: omit_day, form_group: form_group, wildcards: wildcards, **kw_args, &block).html
27
+ end
28
+
29
+ def govuk_collection_radio_buttons(*args, label:, **kw_args)
30
+ super(*args, legend: label, **kw_args)
31
+ end
32
+ deprecate govuk_collection_radio_buttons: 'govuk_collection_radio_buttons is deprecated - please use collection_radio_buttons instead and read the documentation as it makes your code simpler'
33
+
34
+ def collection_radio_buttons(attribute, collection = i18n_options_for(attribute), key_method = :first, value_method = :last, *args, label: true, hint: true, optional: false, include_hidden: false, **kw_args)
35
+ __getobj__.govuk_collection_radio_buttons(attribute, collection, key_method, value_method, *args, legend: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), include_hidden: include_hidden, **kw_args)
36
+ end
37
+
38
+ def collection_select(attribute, collection = i18n_options_for(attribute), key_method = :first, value_method = :last, *args, label: true, hint: true, optional: false, html_options: {}, **kw_args)
39
+ __getobj__.govuk_collection_select(attribute, collection, key_method, value_method, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), html_options: { class: 'govuk-!-width-two-thirds' }.merge(html_options), **kw_args)
40
+ end
41
+ deprecate govuk_collection_select: 'govuk_collection_select is deprecated - please use collection_select instead and read the documentation as it makes your code simpler'
42
+
43
+ def govuk_collection_check_boxes(*args, label:, **kw_args)
44
+ super(*args, legend: label, **kw_args)
45
+ end
46
+ deprecate govuk_collection_check_boxes: 'govuk_collection_check_boxes is deprecated - please use collection_check_boxes instead and read the documentation as it makes your code simpler'
47
+
48
+ def collection_check_boxes(attribute, collection = i18n_options_for(attribute), key_method = :first, value_method = :last, *args, label: true, hint: true, optional: false, **kw_args)
49
+ __getobj__.govuk_collection_check_boxes(attribute, collection, key_method, value_method, *args, legend: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), **kw_args)
50
+ end
51
+
52
+ def check_boxes_fieldset(attribute_name, label: true, caption: {}, hint: true, small: false, classes: nil, form_group: {}, multiple: true, optional: false, include_hidden: true, &block)
53
+ __getobj__.govuk_check_boxes_fieldset(attribute_name, legend: normalize_label(attribute_name, label, optional), caption: caption, hint: normalize_hint(attribute_name, hint), small: small, classes: classes, form_group: form_group, multiple: multiple, &block)
54
+ end
55
+
56
+ def singular_check_box(attribute_name, value: true, unchecked_value: false, fieldset_label: true, fieldset_caption: {}, fieldset_hint: true, optional: false, include_hidden: true, label: fieldset_label, hint: false)
57
+ check_boxes_fieldset(attribute_name, multiple: false, label: fieldset_label, hint: fieldset_hint, include_hidden: include_hidden) do
58
+ result = []
59
+ result << __getobj__.hidden_field(attribute_name, value: unchecked_value) if include_hidden
60
+ result << check_box(attribute_name, value, unchecked_value, multiple: false, label: normalize_check_box_label(attribute_name, label, optional), hint: hint)
61
+ safe_join(result)
62
+ end
63
+ end
64
+
65
+ def govuk_fieldset(*args, label:, **kw_args)
66
+ super(*args, legend: label, **kw_args)
67
+ end
68
+
69
+ def fieldset(*args, label:, **kw_args, &block)
70
+ __getobj__.govuk_fieldset(*args, legend: normalize_fieldset_label(nil, label, false), **kw_args, &block)
71
+ end
72
+
73
+ def govuk_email_field(*args, **kw_args)
74
+ super(*args, spellcheck: false, **kw_args)
75
+ end
76
+ deprecate govuk_email_field: 'govuk_email_field is deprecated - please use email_field instead and read the documentation as it makes your code simpler'
77
+
78
+ def email_field(attribute, *args, label: true, hint: true, width: 'two-thirds', optional: false, **kw_args)
79
+ __getobj__.govuk_email_field(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), width: width, **kw_args)
80
+ end
81
+
82
+ def govuk_phone_field(*args, **kw_args)
83
+ super(*args, autocomplete: 'tel', **kw_args)
84
+ end
85
+ deprecate govuk_phone_field: 'govuk_phone_field is deprecated - please use phone_field instead and read the documentation as it makes your code simpler'
86
+
87
+ def phone_field(attribute, *args, label: true, hint: true, width: 'two-thirds', optional: false, **kw_args)
88
+ __getobj__.govuk_phone_field(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), width: width, **kw_args)
89
+ end
90
+
91
+ def govuk_text_field(attribute, *args, label: true, hint: true, width: 'two-thirds', optional: false, **kw_args)
92
+ super(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), width: width, **kw_args)
93
+ end
94
+ deprecate govuk_text_field: 'govuk_text_field is deprecated - please use text_field instead and read the documentation as it makes your code simpler'
95
+
96
+ def text_field(attribute, *args, label: true, hint: true, width: 'two-thirds', optional: false, **kw_args)
97
+ __getobj__.govuk_text_field(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), width: width, **kw_args)
98
+ end
99
+
100
+ def text_area(attribute, *args, label: true, hint: true, optional: false, **kw_args)
101
+ __getobj__.govuk_text_area(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), **kw_args)
102
+ end
103
+ deprecate govuk_text_area: 'govuk_text_area is deprecated - please use text_area instead and read the documentation as it makes your code simpler'
104
+
105
+ def file_field(attribute, *args, label: true, hint: true, optional: false, **kw_args)
106
+ __getobj__.govuk_file_field(attribute, *args, label: normalize_label(attribute, label, optional), hint: normalize_hint(attribute, hint), **kw_args)
107
+ end
108
+ deprecate govuk_file_field: 'govuk_file_field is deprecated - please use file_field instead and read the documentation as it makes your code simpler'
109
+
110
+ def file_dropzone_field(attribute, *args, label: true, hint: true, optional: false, upload_button: true, remove_file_button: true, file_selected_text: true, caption: {}, form_group: {}, accepted_files: nil, type: 'text/csv', **kw_args, &block)
111
+ Elements::FileDropzone.new(self,
112
+ object_name,
113
+ attribute, hint: normalize_hint(attribute, hint),
114
+ label: normalize_label(attribute, label, optional),
115
+ button_text: normalize_text_argument(attribute, upload_button, 'button_text'),
116
+ remove_file_button_text: normalize_text_argument(attribute, remove_file_button, 'remove_file_button_text'),
117
+ file_selected_text: normalize_text_argument(attribute, file_selected_text, 'file_selected_text'),
118
+ caption: caption,
119
+ form_group: form_group,
120
+ accepted_files: accepted_files,
121
+ type: type,
122
+ template: template,
123
+ **kw_args).html
124
+ end
125
+
126
+ def check_box(attribute, *args, label: true, hint: true, optional: false, **kw_args)
127
+ __getobj__.govuk_check_box(attribute, *args, label: normalize_check_box_label(attribute, label, optional), hint: normalize_hint(attribute, hint), **kw_args)
128
+ end
129
+ deprecate govuk_check_box: 'govuk_check_box is deprecated - please use check_box instead and read the documentation as it makes your code simpler'
130
+
131
+ def submit(*args)
132
+ __getobj__.govuk_submit(*args)
133
+ end
134
+
135
+ def revealed_content(attribute, values:, classes: [], multiple: false, tag: 'div', &block)
136
+ # div data-reveal-on-selector='input[name="employment[current_situation]"]' data-reveal-on-value="still_employed"
137
+ name = "#{__field_name_for(attribute)}#{multiple ? '[]' : ''}"
138
+ content_tag tag, class: classes, data: {
139
+ 'reveal-on-selector': "input[name=\"#{name}\"]",
140
+ 'reveal-on-value': values.to_json,
141
+ 'module': 'et-gds-design-system-reveal-on-radio-button'
142
+ } do
143
+ capture(&block)
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ attr_reader :template
150
+
151
+ def __field_name_for(attribute)
152
+ text_input = capture do
153
+ text_field(attribute, label: false, hint: false)
154
+ end
155
+ text_input.match(/name="(.*?)"/)[1]
156
+ end
157
+
158
+ def normalize_label(attribute, label, optional)
159
+ case label
160
+ when String then LABEL_DEFAULTS.merge(text: __with_optional(label, optional))
161
+ when Hash then LABEL_DEFAULTS.merge(optional ? label.merge(text: __with_optional(label[:text], optional)) : label)
162
+ when FalseClass then { text: false }
163
+ when TrueClass then LABEL_DEFAULTS.merge(text: __with_optional(@template.t(".#{attribute}.label"), optional))
164
+ else label
165
+ end
166
+ end
167
+
168
+ def normalize_check_box_label(attribute, label, optional)
169
+ case label
170
+ when String then CHECK_BOX_LABEL_DEFAULTS.merge(text: __with_optional(label, optional))
171
+ when Hash then CHECK_BOX_LABEL_DEFAULTS.merge(optional ? label.merge(text: __with_optional(label[:text], optional)) : label)
172
+ when FalseClass then { text: false }
173
+ when TrueClass then CHECK_BOX_LABEL_DEFAULTS.merge(text: __with_optional(@template.t(".#{attribute}.label"), optional))
174
+ else label
175
+ end
176
+ end
177
+
178
+ def normalize_fieldset_label(attribute, label, optional)
179
+ case label
180
+ when String then FIELDSET_LABEL_DEFAULTS.merge(text: __with_optional(label, optional))
181
+ when Hash then FIELDSET_LABEL_DEFAULTS.merge(optional ? label.merge(text: __with_optional(label[:text], optional)) : label)
182
+ when FalseClass then { text: false }
183
+ when TrueClass then FIELDSET_LABEL_DEFAULTS.merge(text: __with_optional(@template.t(".#{attribute}.label"), optional))
184
+ else label
185
+ end
186
+ end
187
+
188
+ def normalize_hint(attribute, hint)
189
+ case hint
190
+ when String then HINT_DEFAULTS.merge(text: hint)
191
+ when Hash then HINT_DEFAULTS.merge(hint)
192
+ when TrueClass then __hint_hash(attribute)
193
+ when FalseClass then { text: false }
194
+ else hint
195
+ end
196
+ end
197
+
198
+ def normalize_text_argument(attribute, arg, i18n_key)
199
+ case arg
200
+ when TrueClass then @template.t(".#{attribute}.#{i18n_key}", raise: true)
201
+ when FalseClass then nil
202
+ else arg
203
+ end
204
+ rescue I18n::MissingTranslationData
205
+ nil
206
+ end
207
+
208
+ def __hint_hash(attribute)
209
+ hint_text = __hint_text(attribute)
210
+ return {} if hint_text.nil?
211
+
212
+ HINT_DEFAULTS.merge(text: hint_text)
213
+ end
214
+
215
+ def __hint_text(attribute)
216
+ @template.t(".#{attribute}.hint", raise: true)
217
+ rescue I18n::MissingTranslationData
218
+ nil
219
+ end
220
+
221
+ def __upload_button_text(attribute)
222
+ @template.t(".#{attribute}.button_text", raise: true)
223
+ rescue I18n::MissingTranslationData
224
+ nil
225
+ end
226
+
227
+ def __with_optional(label_text, optional)
228
+ return label_text if label_text.nil? || !optional
229
+
230
+ "#{label_text} #{@template.t(OPTIONAL_I18N_KEY)}"
231
+ end
232
+
233
+ def i18n_options_for(attribute)
234
+ @template.t(".#{attribute}.options").to_a.map do |item|
235
+ item[0] = item[0].to_s
236
+ item
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,3 @@
1
+ module EtGdsDesignSystem
2
+ VERSION = '5.0.0'
3
+ end
@@ -0,0 +1,7 @@
1
+ require "et_gds_design_system/engine"
2
+ require "et_gds_design_system/form/builder"
3
+ module EtGdsDesignSystem
4
+ def self.form_builder_class
5
+ Form::Builder
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ require 'et_gds_design_system/version'
2
+ install_template_path = File.expand_path("../../install/template.rb", __dir__).freeze
3
+ bin_path = ENV["BUNDLE_BIN"] || "./bin"
4
+ namespace :et_gds_design_system do
5
+ desc "Installs everything needed into a rails 6+ app"
6
+ task :install do
7
+ if Rails::VERSION::MAJOR >= 5
8
+ exec "#{RbConfig.ruby} #{bin_path}/rails app:template LOCATION=#{install_template_path}"
9
+ else
10
+ exec "#{RbConfig.ruby} #{bin_path}/rake rails:template LOCATION=#{install_template_path}"
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,221 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: et_gds_design_system
3
+ version: !ruby/object:Gem::Version
4
+ version: 5.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gary Taylor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: govuk_design_system_formbuilder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webpacker
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-proxy
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: capybara
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: selenium-webdriver
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.142'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.142'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webdrivers
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.3'
125
+ - !ruby/object:Gem::Dependency
126
+ name: capybara-screenshot
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: site_prism
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: activerecord-nulldb-adapter
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.4'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.4'
167
+ description: Description of EtGdsDesignSystem.
168
+ email:
169
+ - gary.taylor@hismessages.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - MIT-LICENSE
175
+ - README.md
176
+ - Rakefile
177
+ - app/assets/config/et_gds_design_system_manifest.js
178
+ - app/helpers/et_gds_design_system/file_dropzone_helper.rb
179
+ - app/javascript/components.js
180
+ - app/javascript/components/DropzoneUploader.js
181
+ - app/javascript/components/DropzoneUploader/preview-template.html
182
+ - app/javascript/components/DropzoneUploader/stylesheet.scss
183
+ - app/javascript/components/RevealOnRadioButton.js
184
+ - app/types/et_gds_design_system/azure_file.rb
185
+ - app/types/et_gds_design_system/date_without_day_type.rb
186
+ - app/views/et_gds_design_system/elements/file_dropzone/_template.html.erb
187
+ - config/initializers/type.rb
188
+ - config/routes.rb
189
+ - lib/et_gds_design_system.rb
190
+ - lib/et_gds_design_system/api_proxy.rb
191
+ - lib/et_gds_design_system/elements/date.rb
192
+ - lib/et_gds_design_system/elements/file_dropzone.rb
193
+ - lib/et_gds_design_system/engine.rb
194
+ - lib/et_gds_design_system/form/builder.rb
195
+ - lib/et_gds_design_system/version.rb
196
+ - lib/tasks/et_gds_design_system_tasks.rake
197
+ homepage: http://www.google.com
198
+ licenses:
199
+ - MIT
200
+ metadata: {}
201
+ post_install_message:
202
+ rdoc_options: []
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ requirements: []
216
+ rubyforge_project:
217
+ rubygems_version: 2.7.6
218
+ signing_key:
219
+ specification_version: 4
220
+ summary: Summary of EtGdsDesignSystem.
221
+ test_files: []