Current section

48 Versions

Jump to

Compare versions

15 files changed
+233 additions
-104 deletions
  @@ -1,5 +1,68 @@
1 1 # Changelog
2 2
3 + ## 0.9.0
4 +
5 + ### Changes
6 +
7 + - [Text input](`PrimerLive.Component.text_input/1`): Set disabled color on read-only field with inset style.
8 + - [Checkbox group](`PrimerLive.Component.checkbox_group/1`) and [Radio group](`PrimerLive.Component.radio_group/1`): Show required marker in legend.
9 + - [Action menu](`PrimerLive.Component.action_menu/1`) and [Select menu](`PrimerLive.Component.select_menu/1`): Added attribute `offset_x` to define the absolute offset for the menu on the horizontal axis.
10 + - [Header](`PrimerLive.Component.header/1`): added attributes `variant="base"` to create a light colored header, and `is_compact` for a smaller vertical height.
11 + - Updated upstream Primer Design System libraries. This update includes a number of changes to modified CSS Custom Properties.
12 + - Updated upstream dependency `@primer/css` to `21.5.0`.
13 + - Added `@primer/view-components` version `0.34.0`. This is the Rails version of Primer Design, which is the most developed so far.
14 + - Updated [Octicon](`PrimerLive.Component.octicon/1`) icons to version `v19.12.0`.
15 + - Added support for right-to-left languages.
16 + - Added support for `@scope`, allowing PrimerLive to be used alongside other CSS libraries. See usage instructions in [Installation](doc-extra/installation.md#scoped-css).
17 + - Added documentation [Styling](doc-extra/styling.md). This contains notes about styling with custom CSS and pre-made classes, reusing styled components and support for right-to-left languages.
18 +
19 + ### Depreciations
20 +
21 + Standalone `form_control` as wrapper is soft-deprecated.
22 +
23 + The use of `form_control` as wrapper component around a form input component was causing compatibility issues with displaying validation messages. Since input components should be able to display a validation message even when not wrapped inside a `form_control`, it became difficult to distinguish between a validation messages originating from the `form_control` and one originating from the nested input.
24 +
25 + With the introduction of `checkbox_group` and `radio_group` in version 0.5, there has been less need for a standalone form control wrapper.
26 +
27 + Overall, moving `form_control` to the background and using it only as an internal component resolves a range of problems.
28 +
29 + See "Updating to 0.9" below.
30 +
31 + ### Removals
32 +
33 + - `form_group` was soft-deprecated in 0.5.0 and has been removed, along with component attributes `form_group` and `is_form_group`.
34 +
35 + ### Bug fixes
36 +
37 + - [Checkbox group](`PrimerLive.Component.checkbox_group/1`) and [Radio group](`PrimerLive.Component.radio_group/1`): Restored display of validation message.
38 + - [Textarea](`PrimerLive.Component.textarea/1`): Set correct success color when displaying success feedback.
39 +
40 + ### Updating to 0.9
41 +
42 + #### form_control
43 +
44 + There have 2 ways to create a form control: as a wrapper, and as an input attribute. If you've been using `form_control` as wrapper around inputs, change:
45 +
46 + ```
47 + <.form :let={f} for={@changeset}>
48 + <.form_control form={f} field={:first_name} for="first-name">
49 + <.text_input form={f} field={:first_name} id="first-name" />
50 + </.form_control>
51 + </.form>
52 + ```
53 +
54 + to
55 +
56 + ```
57 + <.form :let={f} for={@changeset}>
58 + <.text_input form={f} field={:first_name} id="first-name" is_form_control />
59 + </.form>
60 + ```
61 +
62 + #### CSS Custom Properties (Variables)
63 +
64 + If you are using CSS Custom Properties from the Primer Design System, these may need to be updated. Verify the current available options in [primer-live.css](https://github.com/ArthurClemens/primer_live/blob/development/priv/static/primer-live.css).
65 +
3 66 ## 0.8.0
4 67
5 68 ### Refactoring of dialogs, drawers, and menus
  @@ -515,3 +578,7 @@ Bug fix:
515 578 ## 0.1.1
516 579
517 580 First release.
581 +
582 + ```
583 +
584 + ```
  @@ -1,14 +1,14 @@
1 1 # PrimerLive
2 2
3 - An implementation of GitHub's [Primer Design System](https://primer.style/design) for Phoenix LiveView.
3 + An implementation of GitHub's [Primer Design System](https://primer.style/design) for Phoenix LiveView and regular (non-LiveView) views in Phoenix applications.
4 4
5 - Primer Design provides a strong base for creating data driven applications such as rich CRUD applications with interactive forms.
5 + PrimerLive provides a strong base for creating data driven applications such as rich CRUD applications with interactive forms that integrate with Phoenix Forms, Ash Forms and Ecto Changesets.
6 6
7 - All PrimerLive components accept the `class` attribute for customisations (and often the `classes` struct to address inner elements). [Primer's utility classes](https://primer.style/design/foundations/css-utilities/getting-started) allow a wide range of customisations without having to write custom styles.
7 + Menus and dialogs allow for in-page viewing and editing of data, without leaving the current page. Alternatively, menus and dialogs can be invoked when visiting a specific route.
8 8
9 - PrimerLive components can be used in [Phoenix LiveView pages](https://github.com/phoenixframework/phoenix_live_view) and regular (non-LiveView) views in Phoenix applications.
9 + Components (and their inner elements) can be styled with custom CSS, or by passing pre-made utility classes.
10 10
11 - Forms created with [Ash Framework](https://www.ash-hq.org/) are supported.
11 + Right-to-left languages are supported.
12 12
13 13 ## Documentation
  @@ -1,7 +1,7 @@
1 1 {<<"links">>,
2 2 [{<<"GitHub">>,<<"https://github.com/ArthurClemens/primer_live">>}]}.
3 3 {<<"name">>,<<"primer_live">>}.
4 - {<<"version">>,<<"0.8.0">>}.
4 + {<<"version">>,<<"0.9.0">>}.
5 5 {<<"description">>,
6 6 <<"An implementation of GitHub's Primer Design System for Phoenix LiveView.">>}.
7 7 {<<"elixir">>,<<"~> 1.17">>}.
  @@ -20,10 +20,12 @@
20 20 <<"LICENSE.md">>,<<"priv/static">>,<<"priv/static/primer-live.cjs.js.map">>,
21 21 <<"priv/static/primer-live.css">>,<<"priv/static/primer-live.esm.js">>,
22 22 <<"priv/static/primer-live.cjs.js">>,<<"priv/static/prompt.d.ts">>,
23 - <<"priv/static/primer-live.min.css">>,<<"priv/static/primer-live.min.js">>,
24 - <<"priv/static/primer-live.js">>,<<"priv/static/index.d.ts">>,
25 - <<"priv/static/primer-live.esm.js.map">>,<<"CHANGELOG.md">>,
26 - <<"package.json">>]}.
23 + <<"priv/static/primer-live.min.css">>,
24 + <<"priv/static/primer-live-scoped.css">>,
25 + <<"priv/static/primer-live-scoped.min.css">>,
26 + <<"priv/static/primer-live.min.js">>,<<"priv/static/primer-live.js">>,
27 + <<"priv/static/index.d.ts">>,<<"priv/static/primer-live.esm.js.map">>,
28 + <<"CHANGELOG.md">>,<<"package.json">>]}.
27 29 {<<"requirements">>,
28 30 [[{<<"name">>,<<"ecto">>},
29 31 {<<"app">>,<<"ecto">>},
unknownlib/component.ex
File is too large to be displayed (100 KB limit).
  @@ -551,70 +551,80 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
551 551
552 552 ## Tests
553 553
554 - iex> PrimerLive.Helpers.AttributeHelpers.input_id("my-input-id", nil, nil, "", nil)
554 + iex> PrimerLive.Helpers.AttributeHelpers.input_id("my-input-id", nil, nil, "", nil, false)
555 555 "my-input-id"
556 556
557 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, "my-id", nil, "", nil)
557 + iex> PrimerLive.Helpers.AttributeHelpers.input_id("my-input-id", nil, nil, "", nil, true)
558 + "my-input-id"
559 +
560 + iex> PrimerLive.Helpers.AttributeHelpers.input_id("my-input-id", nil, nil, "", "my-value", true)
561 + "my-input-id-my-value"
562 +
563 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, "my-id", nil, "", nil, false)
558 564 "my-id"
559 565
560 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "", nil)
566 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "", nil, false)
561 567 nil
562 568
563 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "[my-input-name]", nil)
569 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "[my-input-name]", nil, false)
564 570 "[my-input-name]"
565 571
566 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "[my-input-name][]", nil)
572 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :select, "[my-input-name][]", nil, false)
567 573 "[my-input-name]"
568 574
569 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "", nil)
575 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "", nil, false)
570 576 nil
571 577
572 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "my-input-name", nil)
578 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "my-input-name", nil, false)
573 579 "my-input-name"
574 580
575 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "my-input-name", "my-value")
581 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "my-input-name", "my-value", false)
576 582 "my-input-name[my-value]"
577 583
578 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name]", "my-value")
584 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name]", "my-value", false)
579 585 "[my-input-name][my-value]"
580 586
581 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name][]", "my-value")
587 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name][]", "my-value", false)
582 588 "[my-input-name][my-value]"
583 589
584 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name][]", nil)
590 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :checkbox, "[my-input-name][]", nil, false)
585 591 "[my-input-name][]"
586 592
587 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "", nil)
593 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "", nil, false)
588 594 nil
589 595
590 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "my-input-name", nil)
596 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "my-input-name", nil, false)
591 597 "my-input-name"
592 598
593 - iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "my-input-name", "my-value")
599 + iex> PrimerLive.Helpers.AttributeHelpers.input_id(nil, nil, :radio_button, "my-input-name", "my-value", false)
594 600 "my-input-name[my-value]"
595 601
596 602 """
597 - def input_id(input_id, _id, _input_type, _input_name, _value_for_derived_label)
603 + def input_id(input_id, _id, _input_type, _input_name, value_for_derived_label, is_multiple)
604 + when not is_nil(input_id) and is_multiple and is_binary(value_for_derived_label),
605 + do: "#{input_id}-#{value_for_derived_label}"
606 +
607 + def input_id(input_id, _id, _input_type, _input_name, _value_for_derived_label, _is_multiple)
598 608 when not is_nil(input_id),
599 609 do: input_id
600 610
601 - def input_id(_input_id, id, _input_type, _input_name, _value_for_derived_label)
611 + def input_id(_input_id, id, _input_type, _input_name, _value_for_derived_label, _is_multiple)
602 612 when not is_nil(id),
603 613 do: id
604 614
605 - def input_id(_input_id, _id, input_type, "", _value_for_derived_label)
615 + def input_id(_input_id, _id, input_type, "", _value_for_derived_label, _is_multiple)
606 616 when input_type === :select,
607 617 do: nil
608 618
609 - def input_id(_input_id, _id, input_type, input_name, _value_for_derived_label)
619 + def input_id(_input_id, _id, input_type, input_name, _value_for_derived_label, _is_multiple)
610 620 when input_type === :select,
611 621 do: input_name |> String.replace(~r/\[\]$/, "")
612 622
613 - def input_id(_input_id, _id, input_type, "", value_for_derived_label)
623 + def input_id(_input_id, _id, input_type, "", value_for_derived_label, _is_multiple)
614 624 when input_type === :checkbox or input_type === :radio_button,
615 625 do: value_for_derived_label
616 626
617 - def input_id(_input_id, _id, input_type, input_name, value_for_derived_label)
627 + def input_id(_input_id, _id, input_type, input_name, value_for_derived_label, _is_multiple)
618 628 when (input_type === :checkbox or input_type === :radio_button) and is_binary(input_name) do
619 629 cond do
620 630 String.match?(input_name, ~r/\[\]$/) ->
  @@ -628,8 +638,10 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
628 638 end
629 639 end
630 640
631 - def input_id(_input_id, _id, _input_type, "", _value_for_derived_label), do: nil
632 - def input_id(_input_id, _id, _input_type, input_name, _value_for_derived_label), do: input_name
641 + def input_id(_input_id, _id, _input_type, "", _value_for_derived_label, _is_multiple), do: nil
642 +
643 + def input_id(_input_id, _id, _input_type, input_name, _value_for_derived_label, _is_multiple),
644 + do: input_name
633 645
634 646 @spec cleanup_id(nil | binary) :: nil | binary
635 647 def cleanup_id(id) when is_nil(id), do: nil
  @@ -650,10 +662,6 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
650 662 # ID and label
651 663 id_attrs = common_id_attrs(assigns, input_type, common_shared_attrs)
652 664
653 - # Form group
654 - form_control_attrs =
655 - common_form_control_attrs(assigns, id_attrs.input_id, common_shared_attrs)
656 -
657 665 # Field state
658 666 field_state_attrs =
659 667 common_field_state_attrs(
  @@ -662,6 +670,11 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
662 670 common_shared_attrs
663 671 )
664 672
673 + # Form control
674 + form_control_attrs =
675 + common_form_control_attrs(assigns, id_attrs.input_id, common_shared_attrs)
676 + |> Map.merge(field_state_attrs |> Map.drop([:caption]))
677 +
665 678 [
666 679 common_shared_attrs,
667 680 id_attrs,
  @@ -708,8 +721,16 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
708 721 value_for_derived_label = checked_value || value
709 722
710 723 input_id =
711 - input_id(assigns[:input_id], id, input_type, input_name, value_for_derived_label)
712 - |> create_dom_id()
724 + assigns.input_id ||
725 + input_id(
726 + assigns[:input_id],
727 + id,
728 + input_type,
729 + input_name,
730 + value_for_derived_label,
731 + is_multiple
732 + )
733 + |> create_dom_id()
713 734
714 735 derived_label =
715 736 case input_type do
  @@ -732,31 +753,18 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
732 753 form: form,
733 754 field_or_name: field_or_name
734 755 }) do
735 - deprecated_form_group = assigns[:form_group]
736 - deprecated_is_form_group = !!assigns[:is_form_group]
737 - deprecated_has_form_group = deprecated_is_form_group || !!deprecated_form_group
756 + form_control = assigns[:form_control]
757 + is_form_control = assigns[:is_form_control] || !!form_control
738 758
739 - ComponentHelpers.deprecated_message(
740 - "Deprecated attr form_group: use form_control. Since 0.5.0.",
741 - !is_nil(assigns[:form_group])
742 - )
743 -
744 - ComponentHelpers.deprecated_message(
745 - "Deprecated attr is_form_group: use is_form_control. Since 0.5.0.",
746 - assigns[:is_form_group] == true
747 - )
748 -
749 - form_control = assigns[:form_control] || deprecated_form_group
750 - is_form_control = assigns[:is_form_control] || !!form_control || deprecated_is_form_group
751 -
752 - has_form_control = is_form_control || deprecated_has_form_group
759 + has_form_control = is_form_control
753 760
754 761 form_control_attrs =
755 762 Map.merge(form_control || %{}, %{
756 763 form: form,
757 764 field: field_or_name,
765 + input_id: input_id,
758 766 for: input_id,
759 - deprecated_has_form_group: deprecated_has_form_group
767 + is_full_width: assigns[:is_full_width]
760 768 })
761 769
762 770 %{
  @@ -765,7 +773,7 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
765 773 }
766 774 end
767 775
768 - defp common_field_state_attrs(assigns, %{input_name: input_name, input_id: input_id}, %{
776 + defp common_field_state_attrs(assigns, %{input_name: input_name, input_id: input_id, id: id}, %{
769 777 form: form,
770 778 field_or_name: field_or_name
771 779 }) do
  @@ -785,10 +793,13 @@ defmodule PrimerLive.Helpers.AttributeHelpers do
785 793 show_message? = !!message && !ignore_errors? && assigns[:type] !== "hidden"
786 794
787 795 validation_message_id =
788 - if !is_nil(field_state.message),
789 - do:
790 - assigns[:validation_message_id] ||
791 - "#{input_id}-validation"
796 + cond do
797 + !show_message? -> nil
798 + assigns[:validation_message_id] -> assigns[:validation_message_id]
799 + input_id -> "#{input_id}-validation"
800 + id -> "#{id}-validation"
801 + true -> random_string()
802 + end
792 803
793 804 validation_marker_class =
794 805 if has_changeset? do
Loading more files…