Hist-A-recommandation-pour-l-implementation-de-dsfr.Rmd
library(shinygouv)
Pour ce faire, nous avons rédigé un tableau comparatif entre les éléments trouvés dans le framework DSFR et {shiny}. Il permet notamment de mettre en évidence la direction technique à employer selon deux méthodes envisagées pour utiliser DSFR dans une application {shiny}.
Utiliser les fonctionnalités de {bslib} pour utiliser le framework DSFR.
Avantages :
Inconvénients:
ThinkR ne peut garantir le succès de cette méthode. Cette méthode n’a jamais été expérimentée.
On utilise seulement le package {shiny} avec des scripts au démarrage pour remplacer les classes bootstrap par les classes de DSFR. Voici une app qui le fait https://github.com/MTES-MCT/dseshiny/blob/main/dseshiny/R/dse_ui_regexp.R
Exemple pour le actionButton:
library(shiny)
addResourcePath("fonts", system.file("dsfr-v1.6.0/dist/fonts", package = "shinygouv"))
ui <- fluidPage(
includeCSS(system.file("dsfr-v1.6.0/dist/dsfr.min.css", package = "shinygouv")),
h2("Exemple avec un bouton"),
br(),
actionButton("test", "test"),
textOutput("texte")
)
remplace_bttn <- function(ui) {
res <- rapply(
ui,
function(attribut) {
gsub(
x = attribut,
pattern = "btn btn-default",
replacement = "fr-btn"
)
},
how = "replace",
classes = "character"
)
}
server <- function(input, output, session) {
output$texte <- renderText({
input$test
})
}
shinyApp(remplace_bttn(ui), server)
Avantages:
Inconvénients:
From scratch
Coder l’équivalent de la partie ‘UI’ {shiny} (ou quasiment) avec le framework DSFR. La partie ‘server’ reposera toujours sur la partie {shiny}. Un exemple : https://gitlab-forge.din.developpement-durable.gouv.fr/dreal-pdl/csd/shiny.dsfr et aussi https://github.com/ThinkR-open/w3css
Exemple de code pour actionButton :
library(shiny)
addResourcePath("fonts", system.file("dsfr-v1.6.0/dist/fonts", package = "shinygouv"))
actionButton_dsfr <- function(inputId, label) {
tags$button(
id = inputId,
class = "fr-btn",
value = 0,
label
)
}
ui <- fluidPage(
tags$head(
includeCSS(system.file("dsfr-v1.6.0/dist/dsfr.min.css", package = "shinygouv")),
tags$script(
"$(document).on('click', '.fr-btn', function(evt) {
var el = evt.target;
while (el.nodeName != 'BUTTON'){
el = el.parentNode;
}
el = $(el);
el.val( parseInt(el.val()) + 1)
el.trigger('updated');
});
var buttons = new Shiny.InputBinding();
$.extend(buttons, {
find: function(scope) {
return $(scope).find('.fr-btn')
},
getValue: function(el) {
console.log($(el))
return parseInt($(el).val())
},
setValue: function(el, value) {
// JS code to set value
},
receiveMessage: function(el, data) {
// this.setValue(el, data);
},
subscribe: function(el, callback) {
$(el).on('updated.buttons', function(e) {
callback();
});
},
unsubscribe: function(el) {
$(el).off('.buttons');
}
});
Shiny.inputBindings.register(buttons);"
)
),
actionButton_dsfr("test", "test"),
)
server <- function(input, output, session) {
observeEvent(input$test, {
message(input$test)
})
}
shinyApp(ui, server)
Ceci sera transformé en fonction et documenté dans un package
Avantages :
Inconvénients:
On peut tout à fait imaginer une fonction qui parcourt le code pour remplacer les appels à {shiny} avec les fonctions {DSFR}.
from scratch mais pas vraiment
On pourrait recoder les inputs en conservant les classes CSS qui permettent l’activation du backend JS (comme pour shinyWidgets).
Exemple pour le actionButton de {shinyWidgets} https://github.com/dreamRs/shinyWidgets/blob/46359eccb5cfaac80cbe2949da231e3416afcc37/R/actionBttn.R#L63
Ou pour notre actionButon :
Le fait de lui donner la classe action-button
lui permet
d’être reconnu par le JS de {shiny} et donc d’avoir une interaction. De
même, le fait de lui donner la classe fr-btn
en plus, lui
permet d’être reconnu par le CSS du DSFR.
library(shiny)
addResourcePath("fonts", system.file("dsfr-v1.6.0/dist/fonts", package = "shinygouv"))
actionButton_dsfr <- function(inputId, label) {
tags$button(
id = inputId,
class = "fr-btn action-button",
value = 0,
label
)
}
ui <- fluidPage(
includeCSS(system.file("dsfr-v1.6.0/dist/dsfr.min.css", package = "shinygouv")),
actionButton_dsfr("test", "test")
)
server <- function(input, output, session) {
observeEvent(input$test, {
message(input$test)
})
}
shinyApp(ui, server)
Avantages :
Néanmoins, le temps gagné sur les inputs basiques pourrait permettre d’implementer de nouveaux inputs si nécéssaire
Inconvénients :
action-button
notre
code ne marchera plus (peu probable…).Les changements sont énumérés:
On peut tout à fait imaginer une fonction qui parcourt le code pour remplacer les appels à {shiny} avec les fonctions {DSFR}.
Les éléments tels que navbarPage()
,
tabPanel()
etc sont possibles dans la limite de ce que
propose le DSFR. Ils nécessitent plus ou moins une demi-journée par
composant (codé avec des htmlTemplates).
Nous préconisons l’option D. Pourquoi ?
Cette approche permet de mettre en avant le travail réalisé sur le
framework DSFR avec une implémentation possible de l’intégralité des
fonctionnalités sans la contrainte et la lourdeur de connaitre le JS.
Elle permet aussi de faciliter la maintenance du package par les futures
mainteneurs. Bien que cette option ne réponde pas directement à
l’objectif :
éviter d'avoir des fonctions spécifiques pour ne pas géner le passage d'un template à un autre
,
on peut tout à fait imaginer une fonction qui parcourt le code pour
remplacer les appels à {shiny} avec les fonctions {DSFR}.