Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat(segmented): ajout du composant contrôle segmenté [DS-3622] #805

Merged
merged 10 commits into from
Nov 16, 2023
5 changes: 3 additions & 2 deletions module/color/function/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
$theme: map.get($parameters, theme);
$settings: _settings($token);
$index: 1;

@if $theme == dark {
$index: 2;
}
Expand All @@ -44,11 +45,11 @@

$hex: list.nth($option, 1);

@if map.get($parameters, hover) {
@if map.get($parameters, hover) == true {
$hex: list.nth($option, 2);
}

@if map.get($parameters, active) {
@if map.get($parameters, active) == true {
$hex: list.nth($option, 3);
}

Expand Down
16 changes: 9 additions & 7 deletions module/color/mixin/_data-uri-svg.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,34 @@
/// @param {Object} $value - le SVG en data-uri
/// @param {String} $prop - propriété sur laquelle est assignée le svg
/// @example @include scheme-element-data-uri-svg(text title grey, false, "<svg><path fill='$COLOR'></path></svg>"));
@mixin data-uri-svg($tokens, $options: (), $value: "<svg><path fill='$COLOR'></path></svg>", $prop: background-image) {
@mixin data-uri-svg($tokens, $options: (), $value: "<svg><path fill='$COLOR'></path></svg>", $prop: background-image, $var: 'data-uri-svg') {
$legacy: map.get($options, legacy);
$important: map.get($options, important);
$tokens: token.normalise($tokens);
$light-colors: colors.from-list($tokens, hex, (theme: light));
$light-colors: colors.from-list($tokens, hex, (theme: light, hover: map.get($options, hover), active: map.get($options, active)));
$light: result.get($light-colors, $value);
$light: specificity.important($light, $important);

@if $legacy and $prop != false {
@include legacy.is(ie11) {
#{$prop}: #{url(utilities.data-uri(string.encode-svg($light, true), svg))};
@if $prop != false {
#{$prop}: #{url(utilities.data-uri(string.encode-svg($light, true), svg))};
}
}
}
@else {
--data-uri-svg: #{url(utilities.data-uri(string.encode-svg($light, false), svg))};
--#{$var}: #{url(utilities.data-uri(string.encode-svg($light, false), svg))};

$dark-colors: colors.from-list($tokens, hex, (theme: dark));
$dark-colors: colors.from-list($tokens, hex, (theme: dark, hover: map.get($options, hover), active: map.get($options, active)));
$dark: result.get($dark-colors, $value);
$dark: specificity.important($dark, $important);

@include selector.theme(dark) {
--data-uri-svg: #{url(utilities.data-uri(string.encode-svg($dark, false), svg))};
--#{$var}: #{url(utilities.data-uri(string.encode-svg($dark, false), svg))};
}

@if $prop != false {
#{$prop}: var(--data-uri-svg);
#{$prop}: var(--#{$var});
}
}
}
1 change: 1 addition & 0 deletions src/component/legacy.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
@import 'radio/legacy';
@import 'card/legacy';
@import 'checkbox/legacy';
@import 'segmented/legacy';
@import 'toggle/legacy';
@import 'skiplink/legacy';
@import 'select/legacy';
Expand Down
17 changes: 11 additions & 6 deletions src/component/link/style/tool/_build.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// @group link
////

@mixin _link-class($base, $size: md, $place: null, $align-on-content: false) {
@mixin _link-class($base, $size: md, $place: null, $align-on-content: false, $append: '') {
$selector: '';
$base: '#{$base}';

Expand All @@ -29,6 +29,10 @@
$selector: $base;
}

@if $append != '' {
$selector: '#{$selector} #{$append}';
}

#{$selector} {
@if $place != null {
@include has-icon {
Expand Down Expand Up @@ -67,6 +71,7 @@
$align-on-content: map-get($settings, align-on-content);
$base: ns(map-get($settings, selector));
$underline: map-get($settings, underline);
$append: map-get($settings, append);

#{$base} {
@include _build-link-base;
Expand All @@ -81,7 +86,7 @@

@if map_get($settings, no-modifier) != true {
@each $size, $size-settings in $sizes {
@include _link-class($base, $size) {
@include _link-class($base, $size, null, false, $append) {
@include _build-link-size($size-settings, $border-radius);

@if map_get($settings, blank) {
Expand All @@ -92,26 +97,26 @@
}

@if $align-on-content {
@include _link-class($base, $size, null, true) {
@include _link-class($base, $size, null, true, $append) {
@include _link-align-on-content($size, null, $size-settings);
}
}

@if $places != null {
@each $place in $places {
@include _link-class($base, $size, $place) {
@include _link-class($base, $size, $place, false, $append) {
@include _build-link-icon($size-settings, $place, $size, true);
}

@if $align-on-content {
@include _link-class($base, $size, $place, true) {
@include _link-class($base, $size, $place, true, $append) {
@include _link-align-on-content($size, $place, $size-settings);
}
}
}

@if index($places, only) == null {
@include _link-class($base, $size, only) {
@include _link-class($base, $size, only, false, $append) {
@include before(none);
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/component/link/style/tool/_nest.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@
$size-settings: map_get($sizes, $size);
$border-radius: map-get($settings, border-radius);
$places: map-get($links-settings, places);
$append: map-get($settings, append);

@if $insert {
$selector: ns(map-get($settings, selector));

@if $append != null {
$selector: '#{$selector} #{$append}';
}
}

@include nest($selector) {
Expand Down
1 change: 1 addition & 0 deletions src/component/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import api from './api.js';
import './accordion/main.js';
import './button/main.js';
import './card/main.js';
import './segmented/main.js';
import './range/main.js';
import './breadcrumb/main.js';
import './tooltip/main.js';
Expand Down
1 change: 1 addition & 0 deletions src/component/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
@import 'radio/main';
@import 'card/main';
@import 'checkbox/main';
@import 'segmented/main';
@import 'toggle/main';
@import 'skiplink/main';
@import 'select/main';
Expand Down
10 changes: 10 additions & 0 deletions src/component/segmented/.package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
id: segmented
title: Contrôle segmenté
description: Le composant "contrôle segmenté" incite l'utilisateur à choisir entre plusieurs options d'affichage disponibles (vues), mutuellement exclusives avec une valeur sélectionnée par défaut.
doc: https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/controle-segmente
wrapper: col-8
style:
- core
- form
script:
- core
2 changes: 2 additions & 0 deletions src/component/segmented/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import api from '../api.js';
export default api;
19 changes: 19 additions & 0 deletions src/component/segmented/example/index.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<% const sample = getSample(include); %>

<%- sample(getText('sample.default', 'segmented'), './sample/segmented-default.ejs', {}, true); %>

<%- sample(getText('sample.sm', 'segmented'), './sample/segmented-default.ejs', {segmented: {size: 'sm'}}, true); %>

<%- sample(getText('sample.legend-inline', 'segmented'), './sample/segmented-default.ejs', {segmented: {legendInline: true}}, true); %>

<%- sample(getText('sample.hint-text', 'segmented'), './sample/segmented-default.ejs', {segmented: {hint: 'texte additionel'}}, true); %>

<%- sample(getText('sample.icon', 'segmented'), './sample/segmented-default.ejs', {segmented: {icon: 'road-map-line'}}, true); %>

<%- sample(getText('sample.no-legend', 'segmented'), './sample/segmented-default.ejs', {segmented: {noLegend: true}}, true); %>

<%- sample(getText('sample.disabled', 'segmented'), './sample/segmented-default.ejs', {segmented: {disabled: true}}, true); %>

<%- section(getText('sample.max', 'segmented'), 'Lorsque la largeur du contrôle segmenté dépasse celle de son conteneur, la légende ne reste pas sur la même ligne. Si cela ne rentre toujours pas, les boutons passent en vertical. Réduisez la fenêtre pour voir le comportement de ce script.', 0) %>

<%- sample('', './sample/segmented-default.ejs', {segmented: {id: 'segmented-max', legendInline: true, icon: 'road-map-line', elements: [{id: 'segmented-max-1', icon: 'star-line', name: 'segmented-max', value: '1', label: 'label long'}, {id: 'segmented-max-2', icon: 'time-line', name: 'segmented-max', value: '2', checked: true, label: 'label trop long'}]}}, true); %>
26 changes: 26 additions & 0 deletions src/component/segmented/example/sample/segmented-default.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<%
const segmented = locals.segmented || {}
const elements = segmented.elements || [];

const id = segmented.id || uniqueId('segmented');
segmented.legend = segmented.legend || getText('fieldset.legend', 'segmented');
const elementLength = elements.length || 0;

for (let i = elementLength + 1; i < elementLength + 4; i++) elements.push({
id: `${id}-${i}`,
label: elements.label || getText('label', 'form'),
name: id,
value: i,
icon: segmented.icon,
checked: i === 2,
disabled: segmented.disabled && i === 3,
});

const data = {
elements: elements,
...segmented,
}

%>

<%- include('../../template/ejs/segmented.ejs', {segmented: data}) %>
15 changes: 15 additions & 0 deletions src/component/segmented/i18n/fr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
title: Contrôle segmenté
description: Le composant "contrôle segmenté" incite l'utilisateur à choisir entre plusieurs options d'affichage disponibles (vues), mutuellement exclusives avec une valeur sélectionnée par défaut.

fieldset:
legend: Légende

sample:
default: Contrôle segmenté simple
sm: Contrôle segmenté taille SM
disabled: Contrôle segmenté désactivé
icon: Contrôle segmenté avec icônes
no-legend: Contrôle segmenté sans légende
legend-inline: Contrôle segmenté avec légende en ligne
hint-text: Contrôle segmenté avec texte d'aide
max: Contrôle segmenté cas maximum (non recommandé)
14 changes: 14 additions & 0 deletions src/component/segmented/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import api from './api.js';
import { Segmented } from './script/segmented/segmented.js';
import { SegmentedElement } from './script/segmented/segmented-element.js';
import { SegmentedSelector } from './script/segmented/segmented-selector.js';
import { SegmentedEmission } from './script/segmented/segmented-emission.js';

api.segmented = {
SegmentedSelector: SegmentedSelector,
SegmentedEmission: SegmentedEmission,
SegmentedElement: SegmentedElement,
Segmented: Segmented
};

export default api;
11 changes: 11 additions & 0 deletions src/component/segmented/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
////
/// Segmented
/// @group segmented
////

@import '../../core/index';
@import '../form/index';
@import '../link/index';

@import 'style/setting';
@import 'style/tool';
16 changes: 16 additions & 0 deletions src/component/segmented/legacy.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
////
/// Segmented Legacy
/// @group segmented
////

@use 'module/path';
@use 'module/shame/media-query';

@include path.to-dist(2);
@include media-query.order;

@import 'index';
@import 'style/legacy';
@import 'style/scheme';

@include _segmented-scheme(true);
6 changes: 6 additions & 0 deletions src/component/segmented/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import api from './index.js';

api.internals.register(api.segmented.SegmentedSelector.SEGMENTED, api.segmented.Segmented);
api.internals.register(api.segmented.SegmentedSelector.SEGMENTED_ELEMENT, api.segmented.SegmentedElement);

export default api;
20 changes: 20 additions & 0 deletions src/component/segmented/main.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
////
/// Segmented Main
/// @group segmented
////

/* ¯¯¯¯¯¯¯¯¯ *\
SEGMENTED
\* ˍˍˍˍˍˍˍˍˍ */

@use 'module/path';
@use 'module/shame/media-query';

@include path.to-dist(2);
@include media-query.order;

@import 'index';
@import 'style/module';
@import 'style/scheme';

@include _segmented-scheme;
18 changes: 18 additions & 0 deletions src/component/segmented/script/segmented/segmented-element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import api from '../../api.js';
import { SegmentedEmission } from './segmented-emission.js';

class SegmentedElement extends api.core.Instance {
static get instanceClassName () {
return 'SegmentedElement';
}

init () {
this.ascend(SegmentedEmission.ADDED);
}

dispose () {
this.ascend(SegmentedEmission.REMOVED);
}
}

export { SegmentedElement };
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import api from '../../api.js';

const SegmentedEmission = {
ADDED: api.internals.ns.emission('segmented', 'added'),
REMOVED: api.internals.ns.emission('segmented', 'removed')
};

export { SegmentedEmission };
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import api from '../../api.js';

export const SegmentedSelector = {
SEGMENTED: api.internals.ns.selector('segmented'),
SEGMENTED_ELEMENTS: api.internals.ns.selector('segmented__elements'),
SEGMENTED_ELEMENT: api.internals.ns.selector('segmented__element input'),
SEGMENTED_LEGEND: api.internals.ns.selector('segmented__legend')
};
Loading