glib-web 6.10.0 → 6.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ebde832f6f50b0556f57e6b2d716d7315fa01c0def0b75953f8ecf5de60ca547
4
- data.tar.gz: 4d217bd99f1a415bca302a08528a1da652788fc5cca031009e132079d2716381
3
+ metadata.gz: a644c2f81a6edaeaf5bb946f57402098bab2f8e841392a57568a76244856be89
4
+ data.tar.gz: 03ab9e4058180c9ecd70f14d6a26e488ca56dcdc1388175393f24c8ed5d4176b
5
5
  SHA512:
6
- metadata.gz: bb08b62b519b2a2cfc7c9b1767fce93c4373b63b43082715211d44d051a58aafa5e94d4d5509fd907e86a2b0f6a4ce9c35ec7842ce29d2d21993cadcdf044796
7
- data.tar.gz: 715c3de7e58cfa4a443cc73b75b5c3d6a47bc5e9eff3eeb5cd812d119e0dff76e5c14832163abeb9ce891ea5c12b4922918b6133aa90a2848ff31fa49f40e664
6
+ metadata.gz: 13fb675a42739c4d67d50b26a359a6cc4136fc695c0f2730d2c21e721b193f955335a39bcab550704bc29cbfb3073569154b7c08b45924de5c576036842fb965
7
+ data.tar.gz: 1610d45e4b2e60d70475115ca741929585939c847108f46e7b5c209cbc5bff7292720ad85e3eced53f43a43efd2c9bb5756ac3067bab586fe0db17a07177efb0
@@ -659,7 +659,10 @@ class Glib::JsonUi::ViewBuilder
659
659
  class ChipGroup < AbstractField
660
660
  color :color
661
661
  array :options
662
- bool :multiple
662
+ # cache: true for the same reason as Upload's — without it a
663
+ # multiple-selection ChipGroup submits under a single key and only the
664
+ # last selected value survives server-side parsing.
665
+ bool :multiple, cache: true
663
666
  end
664
667
 
665
668
  class TimeZone < AbstractField
@@ -797,7 +800,11 @@ class Glib::JsonUi::ViewBuilder
797
800
  include Glib::JsonUi::FileUploadErrorHandler
798
801
 
799
802
  action :onFinishUpload
800
- bool :multiple
803
+ # cache: true so `@multiple` is set before AbstractField#created computes
804
+ # the submit key — without it the `[]` array suffix is dropped and a
805
+ # multi-file submit collapses to the last file server-side (silently
806
+ # saves one Document per drop instead of one per file).
807
+ bool :multiple, cache: true
801
808
  hash :placeholderView, required: [:type, :width, :height], optional: [:url]
802
809
  hash :inputView, optional: [:files, :variant]
803
810
  hash :clipboardView, optional: [:icon]
@@ -855,13 +862,88 @@ class Glib::JsonUi::ViewBuilder
855
862
  end
856
863
  end
857
864
 
865
+ # Signature field that lets the user draw a signature on a canvas and
866
+ # upload it as an image via ActiveStorage direct upload.
867
+ #
868
+ # The form shows a placeholder sized by `width`/`height`; tapping it opens
869
+ # a dialog with the drawing canvas, and Confirm uploads the drawing as a
870
+ # PNG to `directUploadUrl` and submits the resulting signed id under
871
+ # `name`. The placeholder then shows the signature, and reopening the
872
+ # dialog lets the user edit it. Because the canvas is not in the form,
873
+ # the placeholder can be given the same height as a neighbouring input
874
+ # (e.g. a typed-name alternative) without losing drawing space.
875
+ #
876
+ # `label` titles the dialog; `placeholder` replaces the "Tap to sign"
877
+ # prompt.
878
+ #
879
+ # With `typedName` the dialog gains Draw/Type tabs: the user can type
880
+ # their name instead of drawing, and the placeholder then shows the name
881
+ # in a handwriting style (the `glib-sign-typed` hook carries the font).
882
+ # The typed name is submitted under `typedName[:name]`; exactly one of the
883
+ # signed id and the typed name is ever non-blank. `typedName[:value]`
884
+ # pre-populates an existing name.
885
+ #
886
+ # @example Basic signature field
887
+ # form.fields_sign \
888
+ # name: 'user[signature]',
889
+ # label: 'Your signature',
890
+ # directUploadUrl: glib_direct_uploads_url,
891
+ # width: 320,
892
+ # height: 160,
893
+ # validation: { required: { message: 'add your signature!' } }
894
+ #
895
+ # @example Drawn or typed
896
+ # form.fields_sign \
897
+ # name: 'user[signature]',
898
+ # label: 'Your signature',
899
+ # typedName: { name: 'user[signature_name]', label: 'Type your full name', placeholder: 'Full name' },
900
+ # directUploadUrl: glib_direct_uploads_url,
901
+ # width: 320,
902
+ # height: 160
903
+ #
904
+ # @example Compact signature without validation
905
+ # form.fields_sign \
906
+ # id: 'signature_compact',
907
+ # name: 'user[signature_compact]',
908
+ # directUploadUrl: glib_direct_uploads_url,
909
+ # width: 220,
910
+ # height: 100
911
+ #
912
+ # @note A saved signature is a signed id that cannot be redrawn from the
913
+ # canvas: when a record is re-edited the field pre-populates `value`
914
+ # with the existing attachment's signed id (the component renders a
915
+ # read-only preview instead of ink). An untouched field therefore
916
+ # re-submits that same signed id, so consumers should treat a
917
+ # same-signed-id re-attach as "no change". Resize it via
918
+ # `components_set`/`logics_set` with `width`/`height`.
919
+ #
920
+ # @see app/views/json_ui/garage/test_page/fields_sign.json.jbuilder Garage examples
858
921
  class Sign < AbstractField
859
922
  string :directUploadUrl
860
923
  required :directUploadUrl
861
924
 
925
+ # URL of an already-attached signature image to display as a read-only
926
+ # preview (typically `file_url(attachment)` when re-editing a record
927
+ # that has a drawn signature). Pair with `prop:` so the field also
928
+ # submits the existing signed id when left untouched.
929
+ string :fileUrl
930
+
931
+ # Enables the Type tab. `value` pre-populates the previously typed
932
+ # name; `label`/`placeholder` decorate the text input in the dialog.
933
+ # `name` is still accepted but unused: the typed name is submitted
934
+ # through the field's own param (single-param contract), and the
935
+ # server routes it to the name attribute.
936
+ hash :typedName, optional: [:name, :value, :label, :placeholder]
937
+
862
938
  # Override
863
- # Signature field doesn't have default value
864
- def value(value)
939
+ # A stored signature is an attachment -- submit its signed id (mirrors
940
+ # File#determine_value) so re-editing a signed submission pre-fills the
941
+ # field with the existing blob's signed id instead of serializing the
942
+ # whole attachment proxy.
943
+ def determine_value(context, prop)
944
+ if (value = context.field_value(prop)).attached?
945
+ value.signed_id || ''
946
+ end
865
947
  end
866
948
  end
867
949
 
@@ -1,5 +1,8 @@
1
1
  json.title 'Test Page (Fields Sign)'
2
2
 
3
+ # 60x20 ink stand-in used by the pre-filled examples.
4
+ preview_data_uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAAUCAYAAADRA14pAAAAoklEQVR4nO2XUQrAIAxDcwjvf9WNfQzG1NFqUt1mwL8a8hBtxfYzYXSAaC1glVJK2RohOXAJdCS4FNgCGw0tA7YAjQCXAHsBoqAPbzpwa3A19OkLpjkjsAL66gmWOTOo0gtvOJXe/VcP9JpH3DvmewBLkdeUKfaLD09xqSaid7bkqilrS57pKHJCYmWq9uFZQD2ZLLkeB49ZQO/qybX+w1/XDujJvn2bufeCAAAAAElFTkSuQmCC'
5
+
3
6
  page = json_ui_page json
4
7
 
5
8
  render 'json_ui/garage/test_page/header', json: json, page: page
@@ -25,6 +28,11 @@ page.body(
25
28
  form.fields_sign(
26
29
  id: 'signature_main',
27
30
  name: 'user[signature]',
31
+ label: 'Your signature',
32
+ # Single-param contract: the typed name is submitted through the
33
+ # field's own param, so typedName carries only the input's
34
+ # decoration and pre-filled value.
35
+ typedName: { label: 'Type your full name', placeholder: 'Full name' },
28
36
  directUploadUrl: glib_direct_uploads_url,
29
37
  width: 320,
30
38
  height: 160,
@@ -113,7 +121,7 @@ page.body(
113
121
  text: 'Clear value',
114
122
  onClick: ->(action) do
115
123
  action.runMultiple childActions: ->(multiple) do
116
- multiple.components_set targetId: 'signature_main', data: { value: nil }
124
+ multiple.components_set targetId: 'signature_main', data: { value: '' }
117
125
  multiple.logics_set targetId: 'signature_status', data: { text: 'Status: cleared' }
118
126
  end
119
127
  end
@@ -137,7 +145,7 @@ page.body(
137
145
 
138
146
  form.h2 text: 'Edge/advanced'
139
147
  form.spacer height: 8
140
- form.label text: 'Use a small canvas to test tighter layouts.'
148
+ form.label text: 'A small, draw-only slot (no typedName, so the dialog has no tabs).'
141
149
  form.spacer height: 8
142
150
  form.fields_sign(
143
151
  id: 'signature_compact',
@@ -146,6 +154,46 @@ page.body(
146
154
  width: 220,
147
155
  height: 100
148
156
  )
157
+
158
+ form.spacer height: 12
159
+ form.hr width: 'matchParent'
160
+ form.spacer height: 12
161
+
162
+ form.h2 text: 'Pre-filled (re-edit)'
163
+ form.spacer height: 8
164
+ form.label text: 'A saved signature: value carries the signed id, fileUrl renders the preview.'
165
+ form.spacer height: 8
166
+ form.fields_sign(
167
+ id: 'signature_prefilled',
168
+ name: 'user[signature_prefilled]',
169
+ # A stand-in for the signed id the Sign builder derives from
170
+ # `prop:` on a re-edit (see Sign#determine_value).
171
+ value: 'prefilled-signed-id',
172
+ fileUrl: preview_data_uri,
173
+ typedName: { label: 'Type your full name', placeholder: 'Full name' },
174
+ directUploadUrl: glib_direct_uploads_url,
175
+ width: 320,
176
+ height: 160
177
+ )
178
+
179
+ form.spacer height: 12
180
+ form.hr width: 'matchParent'
181
+ form.spacer height: 12
182
+
183
+ form.h2 text: 'Read-only (pre-filled)'
184
+ form.spacer height: 8
185
+ form.label text: 'A saved signature on a read-only field: the preview shows, the edit overlay does not.'
186
+ form.spacer height: 8
187
+ form.fields_sign(
188
+ id: 'signature_readonly',
189
+ name: 'user[signature_readonly]',
190
+ value: 'readonly-signed-id',
191
+ fileUrl: preview_data_uri,
192
+ directUploadUrl: glib_direct_uploads_url,
193
+ width: 320,
194
+ height: 160,
195
+ readOnly: true
196
+ )
149
197
  end
150
198
  )
151
199
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glib-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.10.0
4
+ version: 6.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-02 00:00:00.000000000 Z
11
+ date: 2026-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage