[1.0.2] Notice pattern evolution

Created on 16 April 2024, 7 months ago
Updated 20 September 2024, 2 months ago

Our functional team requests that upon clicking the notice close button, it should save to prevent it from reappearing when changing pages.

Steps to reproduce

When i place my notice block, upon clicking, the notice closes, but upon changing the page, it reappears.

Proposed resolution

I propose modifications to the twig as follows :

{% set variant = variant|default('info') %}

{% if isBlock %}
  {% set block_id = 'fr-notice--block-id' %}
{% else %}
  {% set block_id = 'fr-notice--' ~ random() %}
{% endif %}

<div{{ attributes.addClass('fr-notice').addClass('fr-notice--' ~ variant)}} id= {{ block_id }}>
  <div class="fr-container">
    <div class="fr-notice__body">
    {% if title %}
    <div class="fr-notice__title">
      {{ title }}
    </div>
    {% endif %}
    {% if dismissible %}
      {% set close_title = close_title|default('Close'|t) %}
      {% set event = "const notice = this.parentNode.parentNode.parentNode; notice.parentNode.removeChild(notice); sessionStorage.setItem('is>
      <button onclick="{{ event }}" class="fr-btn fr-btn--close" title="{{ close_title }}">
        {{ close_title }}
      </button>
    {% endif %}
    </div>
  </div>
</div> 

OR

{% set variant = variant|default('info') %}

<div{{ attributes.addClass('fr-notice').addClass('fr-notice--' ~ variant)}} {% if isBlock %} id= 'fr-notice--block-id' {% endif %}>
  <div class="fr-container">
    <div class="fr-notice__body">
    {% if title %}
    <div class="fr-notice__title">
      {{ title }}
    </div>
    {% endif %}
    {% if dismissible %}
      {% set close_title = close_title|default('Close'|t) %}
      {% set event = "const notice = this.parentNode.parentNode.parentNode; notice.parentNode.removeChild(notice); sessionStorage.setItem('is>
      <button onclick="{{ event }}" class="fr-btn fr-btn--close" title="{{ close_title }}">
        {{ close_title }}
      </button>
    {% endif %}
    </div>
  </div>
</div> 

and the .yml like this :

notice:
  label: Notice
  description: Draws the user's attention to information without interrupting his current task. https://www.systeme-de-design.gouv.fr/element>
  variants:
    info:
      label: Information
  settings:
    block_id:
      type: token
      label: ID
      description: "Must start with a letter. Randomly generated if empty."
    dismissible:
      type: boolean
      label: Dismissible?
      description: It’s possible to dismiss any notice inline.
      preview: true
    isBlock:
      type: boolean
      label: Block?
      description: If true, the notice will be assigned a predefined, hard-coded ID attribute.
      preview: false
    close_title:
      type: token
      label: Close button text
      description: Optional. Will be used only if notice is dismissible.
      preview: Hide message
  fields:
    title:
      type: text
      label: Title
      preview: "Notice: Title of an notice" 

<strong>OR</strong>

notice:
  label: Notice
  description: Draws the user's attention to information without interrupting his current task. https://www.systeme-de-design.gouv.fr/element>
  variants:
    info:
      label: Information
  settings:
    dismissible:
      type: boolean
      label: Dismissible?
      description: It’s possible to dismiss any notice inline.
      preview: true
    isBlock:
      type: boolean
      label: Block?
      description: If true, the notice will be assigned a predefined, hard-coded ID attribute.
      preview: false
    close_title:
      type: token
      label: Close button text
      description: Optional. Will be used only if notice is dismissible.
      preview: Hide message
  fields:
    title:
      type: text
      label: Title
      preview: "Notice: Title of an notice" 

AND add a JasavaScript script:

document.addEventListener ('DOMContentLoaded', function() {

let noticeContainer = document.getElementById ('fr-notice--block-id');

if (noticeContainer) {
  let isClose = sessionStorage.getItem('isOpen') === 'false';
  if(isClose) {
  noticeContainer.remove()
  }
}

});

Thank you.

✨ Feature request
Status

Needs work

Version

1.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @yassrzg
  • πŸ‡«πŸ‡·France pdureau Paris
  • πŸ‡«πŸ‡·France pdureau Paris
  • Status changed to Postponed: needs info 7 months ago
  • πŸ‡«πŸ‡·France pdureau Paris

    Hi Yassine,

    That's a good idea, but:

    • let's avoid a constant value in an HTML ID attribute: {% set block_id = 'fr-notice--block-id' %}
    • let's avoid using random() function outside a default() filter: {% set block_id = 'fr-notice--' ~ random() %}
    • the name of the new prop must not be isBlock but something like permanent_state, because of the expected feature

    So, a proposal:

        permanent_state:
          type: boolean
          label: Permanent state?
          description:  If true, the notice will remember its state in between page reloads. Expect a non random block_id value.
          preview: false

    The wording proposal may change.

    With:

    {% set block_id = block_id|default('fr-notice--' ~ random()) %}
    {% set attributes =attributes.setAttribute("id", block_id)  %}
    {% set attributes = permanent_state ? attributes.setAtttibute("data-permanent-state", "true") : attributes %}
    <div{{ attributes.addClass('fr-notice').addClass('fr-notice--' ~ variant)}}>

    So:

    • Can you rebuild your script around this proposal?
    • Do you think upstream DSFR will accept such a proposal?
    • I will need to ask other people to validate such a proposal because we are at the limit between application state and design system.
  • Merge request !70by yassrzg Notice pattern evolution β†’ (Open) created by yassrzg
  • Status changed to Needs work 7 months ago
  • Status changed to Needs review 7 months ago
  • I have adapted the JavaScript script and added a new CSS file 'notice.css'.
    I initialized .fr-notice[data-permanent-state="true"] { display: none; }, to prevent the notice from flickering every time the page changes.
    I added the JavaScript and CSS files to the .libraries.yml file.

  • πŸ‡«πŸ‡·France just_like_good_vibes PARIS

    Hello,
    I have a comment about the Javascript code added.
    why a vanilla JS code instead of a proper drupal JS behavior?
    The JS file is added to the global theme library, therefore in my understanding it should follow best practices β†’ .
    what do you think?
    i can help in writing the code if needed.
    thank you

  • πŸ‡«πŸ‡·France pdureau Paris

    Let's not enforce JS Behaviour here.

  • Status changed to Needs work 6 months ago
  • πŸ‡«πŸ‡·France pdureau Paris

    There are interesting talks in the Drupal community about using WebComponent (with the is attributes instead of the "custom element" syntax) to leverage WebComponents as a standard JS behaviours container where the lifecycle is managed by the browser.

    Do you want to try?

  • πŸ‡«πŸ‡·France pdureau Paris

    Behaviours

    The script to embed: https://git.drupalcode.org/project/ui_suite_dsfr/-/blob/aeb85b6a07c39f1e...

    Example of behaviour:

    Drupal.behaviors.myBehavior = {
        once('myCustomBehavior', 'input.myCustomBehavior', context).forEach(
          function (element) {
               // Your code is here
          }
        );
      }
    };
    

    Asset library management

    In the MR, it is declared at the theme level: https://git.drupalcode.org/project/ui_suite_dsfr/-/blob/aeb85b6a07c39f1e...
    With files in /css and /js folders

    It would be better to add them directly in the component, so they are loaded only when the component is used:

  • πŸ‡«πŸ‡·France pdureau Paris
  • Status changed to Needs review 2 months ago
  • Status changed to Needs work 2 months ago
  • πŸ‡«πŸ‡·France pdureau Paris

    Hello Yassine,

    Looking at https://git.drupalcode.org/project/ui_suite_dsfr/-/merge_requests/70

    • the source branch was not been rebased
    • there is a merge conflict
    • you didn't use the Drupal behabiour notation for your javascript
    • File mode changed from 100644 to 100755 on 124 unrelated files.
  • Merge request !111Resolve #3441191 "Notice" β†’ (Open) created by just_like_good_vibes
  • πŸ‡«πŸ‡·France pdureau Paris

    There is also a feature update to do, because the component has evolved since first implementation:

    Add missing variants

    • title stays a slot, because backward compatibility. You can cerate a 1.1.x issue if you want to convert to prop later
    • Add new string prop: description (a prop because of the P and SPAN element)
    • Add an icon prop with a enum string ("select" in UIP1) (It will be replaced by an icon prop type in 1.1.x branch). What is happening when we also pick a variant with icon?

    For fr-notice__link, 2 possibilities:

      • Add new string prop: button_label
      • Add new url prop: button_url
    • Add a link slot with |add_class() filter
  • πŸ‡«πŸ‡·France just_like_good_vibes PARIS

    What we discussed today in the weekly meeting :

    - for the moment, the notice title stays a slot, but i can be converted to prop when. switching to 1.1.x branch
    - description, link text, link url are introduced as props
    - link title attribute may be a prop with a good default value in twig when injected empty
    - icon will be a prop with the list of classed declared in the yml, as done in button component.
    - the js code is a behavior with a behavior unique name like "ui_suite_dsfr_notice" for Drupal.behaviors.ui_suite_dsfr_notice

  • Pipeline finished with Canceled
    23 days ago
    Total: 139s
    #325866
  • πŸ‡«πŸ‡·France just_like_good_vibes PARIS

    hello, according to our discussions with @yassrzg , i have modified the code.
    please review :)

  • πŸ‡«πŸ‡·France pdureau Paris

    Eslint error: https://git.drupalcode.org/project/ui_suite_dsfr/-/jobs/3218389

    ----

    {% set base_url = base_url %}
    {% set is_external = base_url not in link_url %}
    ...
     {% if link_url and link_text %}<a href="{{ link_url }}" class="fr-notice__link" title="{{ link_description|default(link_text) }}" {% if is_external %} target="_blank" rel="noopener external" {% else %} target="_self" rel="noreferrer"{% endif %} >{{ link_text }}</a>{% endif %}
    

    This is a mess, there are 3 props, 5 variables, and too much logic for a simple link. And {% set base_url = base_url %} is useless.

    Why not a simple slot expecting a link element renderable:

    {{ link.addClass("fr-notice__link") }}
    

    ----

    Instead of hardcoding Button component markup:

    <button class="fr-btn fr-btn--close" title="{{ close_title }}">{{ close_title }}</button>
    

    We can embed the component directly:

    {{ pattern("button", {
      label:  close_title,
     title: close_title
    }) }} 
    

    But we need to add the --close modifier to button component. Not as a variant because it can be combined with existing variants. So, as a boolean prop.

  • πŸ‡«πŸ‡·France pdureau Paris

    I will propose something

  • πŸ‡«πŸ‡·France pdureau Paris

    I have pushed a commit with my proposal

  • πŸ‡«πŸ‡·France just_like_good_vibes PARIS

    yes you are right Pierre, we need to modify the code to target 1.11 only

  • πŸ‡«πŸ‡·France pdureau Paris
  • πŸ‡«πŸ‡·France pdureau Paris
Production build 0.71.5 2024