diff --git a/frontend/src/app/shared/components/datepicker/basic-range-date-picker/basic-range-date-picker.component.ts b/frontend/src/app/shared/components/datepicker/basic-range-date-picker/basic-range-date-picker.component.ts index 35f9f3494f69..699eef974892 100644 --- a/frontend/src/app/shared/components/datepicker/basic-range-date-picker/basic-range-date-picker.component.ts +++ b/frontend/src/app/shared/components/datepicker/basic-range-date-picker/basic-range-date-picker.component.ts @@ -115,6 +115,8 @@ export class OpBasicRangeDatePickerComponent implements OnInit, ControlValueAcce @Input() inputClassNames = ''; + @Input() inDialog = false; + @ViewChild('input') input:ElementRef; stringValue = ''; @@ -199,6 +201,7 @@ export class OpBasicRangeDatePickerComponent implements OnInit, ControlValueAcce !!this.minimalDate && dayElem.dateObj <= this.minimalDate, ); }, + static: this.inDialog, }, this.input.nativeElement as HTMLInputElement, ); diff --git a/frontend/src/app/shared/components/datepicker/basic-single-date-picker/basic-single-date-picker.component.ts b/frontend/src/app/shared/components/datepicker/basic-single-date-picker/basic-single-date-picker.component.ts index 130ab9e59b10..6ebc84272fd7 100644 --- a/frontend/src/app/shared/components/datepicker/basic-single-date-picker/basic-single-date-picker.component.ts +++ b/frontend/src/app/shared/components/datepicker/basic-single-date-picker/basic-single-date-picker.component.ts @@ -52,7 +52,6 @@ import { DayElement } from 'flatpickr/dist/types/instance'; import { populateInputsFromDataset } from '../../dataset-inputs'; import { DeviceService } from 'core-app/core/browser/device.service'; - @Component({ selector: 'op-basic-single-date-picker', templateUrl: './basic-single-date-picker.component.html', @@ -96,6 +95,8 @@ export class OpBasicSingleDatePickerComponent implements ControlValueAccessor, O @Input() remoteFieldKey = null; + @Input() inDialog = false; + @ViewChild('input') input:ElementRef; mobile = false; @@ -179,6 +180,7 @@ export class OpBasicSingleDatePickerComponent implements ControlValueAccessor, O !!this.minimalDate && dayElem.dateObj <= this.minimalDate, ); }, + static: this.inDialog, }, this.input.nativeElement as HTMLInputElement, ); diff --git a/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass b/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass index 35d68546881f..fd1db3299fd8 100644 --- a/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass +++ b/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass @@ -1,6 +1,5 @@ @import '../../app/spot/styles/sass/variables' @import '../../global_styles/openproject/variables' - .op-datepicker-modal display: flex flex-direction: column @@ -88,3 +87,8 @@ &--date-form &:only-child grid-column: 1 / 3 + +.flatpickr-wrapper + // Make flatpickr behave correctly when it is instantiated + // inside a dialog using the static: true option. + width: 100% \ No newline at end of file diff --git a/lib/primer/open_project/forms/date_picker.html.erb b/lib/primer/open_project/forms/date_picker.html.erb new file mode 100644 index 000000000000..7cb0c2f1bf07 --- /dev/null +++ b/lib/primer/open_project/forms/date_picker.html.erb @@ -0,0 +1,11 @@ +<%= render(FormControl.new(input: @input)) do %> + <%= content_tag(:div, class: ("single-date-picker-with-date-icon" if @datepicker_options.delete(:with_date_icon))) do %> + <%= angular_component_tag @datepicker_options.fetch(:component), + inputs: @datepicker_options.merge( + classes: "ng-select--primerized #{@input.invalid? ? '-error' : ''}", + name: @datepicker_options.fetch(:name) { builder.field_name(@input.name) }, + value: @datepicker_options.fetch(:value) { builder.object&.send(@input.name) || @input.value }, + ) + %> + <% end %> +<% end %> diff --git a/lib/primer/open_project/forms/date_picker.rb b/lib/primer/open_project/forms/date_picker.rb new file mode 100644 index 000000000000..e228aa378757 --- /dev/null +++ b/lib/primer/open_project/forms/date_picker.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + module Forms + # :nodoc: + class DatePicker < Primer::Forms::BaseComponent + include AngularHelper + + delegate :builder, :form, :select_options, to: :@input + + def initialize(input:, datepicker_options:) + super() + @input = input + @datepicker_options = datepicker_options + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/input_methods.rb b/lib/primer/open_project/forms/dsl/input_methods.rb index e2151a300dd5..eca21f89ef75 100644 --- a/lib/primer/open_project/forms/dsl/input_methods.rb +++ b/lib/primer/open_project/forms/dsl/input_methods.rb @@ -6,31 +6,39 @@ module Forms module Dsl module InputMethods def autocompleter(**, &) - add_input AutocompleterInput.new(builder: @builder, form: @form, **, &) + add_input AutocompleterInput.new(builder:, form:, **, &) end - def work_package_autocompleter(**, &) - add_input WorkPackageAutocompleterInput.new(builder: @builder, form: @form, **, &) + def color_select_list(**, &) + add_input ColorSelectInput.new(builder:, form:, **, &) + end + + def html_content(**, &) + add_input HtmlContentInput.new(builder:, form:, **, &) end def project_autocompleter(**, &) - add_input ProjectAutocompleterInput.new(builder: @builder, form: @form, **, &) + add_input ProjectAutocompleterInput.new(builder:, form:, **, &) + end + + def range_date_picker(**) + add_input RangeDatePickerInput.new(builder:, form:, **) end def rich_text_area(**) - add_input RichTextAreaInput.new(builder: @builder, form: @form, **) + add_input RichTextAreaInput.new(builder:, form:, **) end - def storage_manual_project_folder_selection(**) - add_input StorageManualProjectFolderSelectionInput.new(builder: @builder, form: @form, **) + def single_date_picker(**) + add_input SingleDatePickerInput.new(builder:, form:, **) end - def color_select_list(**, &) - add_input ColorSelectInput.new(builder:, form:, **, &) + def storage_manual_project_folder_selection(**) + add_input StorageManualProjectFolderSelectionInput.new(builder:, form:, **) end - def html_content(**, &) - add_input HtmlContentInput.new(builder: @builder, form: @form, **, &) + def work_package_autocompleter(**, &) + add_input WorkPackageAutocompleterInput.new(builder:, form:, **, &) end end end diff --git a/lib/primer/open_project/forms/dsl/range_date_picker_input.rb b/lib/primer/open_project/forms/dsl/range_date_picker_input.rb new file mode 100644 index 000000000000..e3a5710228de --- /dev/null +++ b/lib/primer/open_project/forms/dsl/range_date_picker_input.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + module Forms + module Dsl + class RangeDatePickerInput < SingleDatePickerInput + def derive_datepicker_options(options) + options.reverse_merge( + component: "opce-range-date-picker" + ) + end + + def type + :range_date_picker + end + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/single_date_picker_input.rb b/lib/primer/open_project/forms/dsl/single_date_picker_input.rb new file mode 100644 index 000000000000..d0075d8f6903 --- /dev/null +++ b/lib/primer/open_project/forms/dsl/single_date_picker_input.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + module Forms + module Dsl + class SingleDatePickerInput < Primer::Forms::Dsl::Input + attr_reader :name, :label, :datepicker_options + + def initialize(name:, label:, datepicker_options:, **system_arguments) + @name = name + @label = label + @datepicker_options = derive_datepicker_options(datepicker_options) + + super(**system_arguments) + end + + def derive_datepicker_options(options) + options.reverse_merge( + component: "opce-single-date-picker" + ) + end + + def to_component + DatePicker.new(input: self, datepicker_options:) + end + + def type + :single_date_picker + end + + def focusable? + true + end + end + end + end + end +end diff --git a/lookbook/previews/open_project/common/datepicker_preview.rb b/lookbook/previews/open_project/common/datepicker_preview.rb index c9bdeaca41ef..2218686b976c 100644 --- a/lookbook/previews/open_project/common/datepicker_preview.rb +++ b/lookbook/previews/open_project/common/datepicker_preview.rb @@ -28,8 +28,9 @@ class DatepickerPreview < Lookbook::Preview # before using or contributing to date pickers. # # @param value date - def single(value: Time.zone.today.iso8601) - render_with_template(locals: { value: }) + # @param in_dialog toggle + def single(value: Time.zone.today, in_dialog: false) + render_with_template(locals: { value:, in_dialog: }) end ## @@ -48,8 +49,9 @@ def single(value: Time.zone.today.iso8601) # before using or contributing to date pickers. # # @param value text - def range(value: "#{Time.zone.today.iso8601} - #{Time.zone.today.iso8601}") - render_with_template(locals: { value: }) + # @param in_dialog toggle + def range(value: "#{Time.zone.today.iso8601} - #{Time.zone.today.iso8601}", in_dialog: false) + render_with_template(locals: { value:, in_dialog: }) end end end diff --git a/lookbook/previews/open_project/common/datepicker_preview/range.html.erb b/lookbook/previews/open_project/common/datepicker_preview/range.html.erb index 559e35bba55a..7b4f09840fd1 100644 --- a/lookbook/previews/open_project/common/datepicker_preview/range.html.erb +++ b/lookbook/previews/open_project/common/datepicker_preview/range.html.erb @@ -1 +1,55 @@ -<%= tag :'opce-range-date-picker', value: %> +<% + the_form = Class.new(ApplicationForm) do + form do |query_form| + query_form.range_date_picker( + name: :date, + label: 'Date', + value: value, + datepicker_options: { inDialog: in_dialog } + ) + + query_form.range_date_picker( + name: :date, + label: 'Date', + value: value, + datepicker_options: { inDialog: in_dialog } + ) + + query_form.range_date_picker( + name: :date, + label: 'Date', + value: value, + datepicker_options: { inDialog: in_dialog } + ) + end + end +%> + +<% if in_dialog %> + <%= render(Primer::Alpha::Dialog.new(title: "Dialog Title", + size: :large, + open: true, + id: "my-dialog")) do |d| %> + <% d.with_show_button { "Show dialog" } %> + <% d.with_header(variant: :medium) %> + + <%= render(Primer::Alpha::Dialog::Body.new) do + primer_form_with( + url: '/abc', + id: "my-form") do |f| + render(the_form.new(f)) + end + end %> + + <%= d.with_footer do %> + <%= render(Primer::Beta::Button.new(data: { "close-dialog-id": "my-dialog" })) { I18n.t(:button_cancel) } %> + <%= render(Primer::Beta::Button.new(scheme: :primary, type: :submit, form: "my-form")) { I18n.t(:button_apply) } %> + <% end %> + <% end %> +<% else %> + <%= primer_form_with( + url: '/abc', + id: "my-form") do |f| + render(the_form.new(f)) + end %> +<% end %> diff --git a/lookbook/previews/open_project/common/datepicker_preview/single.html.erb b/lookbook/previews/open_project/common/datepicker_preview/single.html.erb index bd6afbdcdc15..8ac6e1f519ee 100644 --- a/lookbook/previews/open_project/common/datepicker_preview/single.html.erb +++ b/lookbook/previews/open_project/common/datepicker_preview/single.html.erb @@ -1 +1,55 @@ -<%= tag :'opce-single-date-picker', value: %> +<% + the_form = Class.new(ApplicationForm) do + form do |query_form| + query_form.single_date_picker( + name: :date, + label: 'Date', + value: value.strftime(I18n.t("date.formats.default")), + datepicker_options: { inDialog: in_dialog } + ) + + query_form.single_date_picker( + name: :date, + label: 'Date', + value: value.strftime(I18n.t("date.formats.default")), + datepicker_options: { inDialog: in_dialog } + ) + + query_form.single_date_picker( + name: :date, + label: 'Date', + value: value.strftime(I18n.t("date.formats.default")), + datepicker_options: { inDialog: in_dialog } + ) + end + end +%> + +<% if in_dialog %> + <%= render(Primer::Alpha::Dialog.new(title: "Dialog Title", + size: :large, + open: true, + id: "my-dialog")) do |d| %> + <% d.with_show_button { "Show dialog" } %> + <% d.with_header(variant: :medium) %> + + <%= render(Primer::Alpha::Dialog::Body.new) do + primer_form_with( + url: '/abc', + id: "my-form") do |f| + render(the_form.new(f)) + end + end %> + + <%= d.with_footer do %> + <%= render(Primer::Beta::Button.new(data: { "close-dialog-id": "my-dialog" })) { I18n.t(:button_cancel) } %> + <%= render(Primer::Beta::Button.new(scheme: :primary, type: :submit, form: "my-form")) { I18n.t(:button_apply) } %> + <% end %> + <% end %> +<% else %> + <%= primer_form_with( + url: '/abc', + id: "my-form") do |f| + render(the_form.new(f)) + end %> +<% end %>