@lab-anssi/ui-kit 1.18.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,17 +15,40 @@
15
15
 
16
16
  ## Storybook des composants
17
17
 
18
- Le storybook des composants est disponible [ici](https://betagouv.github.io/lab-anssi-ui-kit/).
18
+ > Nous parlons de _Storybook_ car c'est le terme généralement employé, mais nous utilisons [Histoire](https://histoire.dev/).
19
+ > Nous avons fait ce choix car au moment de la création de notre repo, Storybook n'était pas compatible Svelte.
19
20
 
20
- Il est construit avec [Histoire](https://histoire.dev/)
21
+ Lors de la release d'une nouvelle version de l'UI Kit, le Storybook des composants [est déployé sur Github Pages : https://betagouv.github.io/lab-anssi-ui-kit/](https://betagouv.github.io/lab-anssi-ui-kit/).
21
22
 
22
23
  ## Architecture de build
23
24
 
24
- Cette librairie a pour objectif de produire des composants Svelte et leurs équivalents [Webcomponent](https://developer.mozilla.org/en-US/docs/Web/API/Web_components).
25
+ Cette librairie a pour objectif de produire des composants Svelte et leurs équivalents [WebComponent](https://developer.mozilla.org/en-US/docs/Web/API/Web_components).
25
26
 
26
27
  L'architecture pour produire du Svelte utilise [SvelteKit](https://svelte.dev/docs/kit/packaging), configuré via le wizard `npx sv create`.
27
- C'est ce qui explique les nombreux fichiers de configuration Svelte (Prettier, Vitest, etc...) : Ils ont été rajoutés par le wizard.
28
+ C'est ce qui explique les nombreux fichiers de configuration Svelte (Prettier, Vitest, etc.) : ils ont été rajoutés par le wizard.
28
29
 
29
- Pour rajouter le build des Webcomponents, on rajoute manuellement un fichier de configuration [`vite.webcomponents.config.ts`](./vite.webcomponents.config.ts). et des appels à la commande `vite -c vite.webcomponents.config.ts build` lors des étapes de build du package.
30
+ Pour rajouter le build des WebComponents, on rajoute manuellement un fichier de configuration [`vite.webcomponents.config.ts`](./vite.webcomponents.config.ts) et des appels à la commande `vite -c vite.webcomponents.config.ts build` lors des étapes de build du package.
30
31
 
31
- Résultat : dans le repertoire `dist/` on retrouvera les composants Svelte et leurs équivalents Webcomponents. Tous le contenu de `dist/` est publié via `npm publish`.
32
+ Résultat : dans le repertoire `dist/` on retrouvera les composants Svelte et leurs équivalents Webcomponents.
33
+ Tout le contenu de `dist/` est publié via `npm publish`.
34
+
35
+ ## Développement en local
36
+
37
+ La commande principale pour le développement en local est `npm run story:dev`.
38
+ La sortie devrait ressembler à :
39
+
40
+ ```shell
41
+
42
+ $ npm run story:dev
43
+
44
+ @lab-anssi/ui-kit@1.19.0 story:dev
45
+ HISTOIRE_ENV=development histoire dev
46
+ Re-optimizing dependencies because lockfile has changed
47
+ Using 5 threads for story collection
48
+ Collect stories start all
49
+ ➜ Local: http://localhost:6006/
50
+ ➜ Network: use --host to expose
51
+ ```
52
+
53
+ Après cette commande, le Storybook local est disponible sur http://localhost:6006/.
54
+ Il devrait ressembler [au Storybook disponible en ligne](https://betagouv.github.io/lab-anssi-ui-kit/).
package/dist/index.d.ts CHANGED
@@ -18,3 +18,5 @@ export { default as PageCrisp } from "./lab/blog/PageCrisp.svelte";
18
18
  export { default as ListeArticles } from "./lab/blog/ListeArticles.svelte";
19
19
  export { default as Icone } from "./lab/Icone.svelte";
20
20
  export { default as Bouton } from "./lab/Bouton.svelte";
21
+ export { default as Lien } from "./lab/Lien.svelte";
22
+ export { default as Tag } from "./lab/Tag.svelte";
package/dist/index.js CHANGED
@@ -18,3 +18,5 @@ export { default as PageCrisp } from "./lab/blog/PageCrisp.svelte";
18
18
  export { default as ListeArticles } from "./lab/blog/ListeArticles.svelte";
19
19
  export { default as Icone } from "./lab/Icone.svelte";
20
20
  export { default as Bouton } from "./lab/Bouton.svelte";
21
+ export { default as Lien } from "./lab/Lien.svelte";
22
+ export { default as Tag } from "./lab/Tag.svelte";
@@ -6,66 +6,122 @@
6
6
  variante: { reflect: false, type: "String", attribute: "variante" },
7
7
  taille: { reflect: false, type: "String", attribute: "taille" },
8
8
  icone: { reflect: false, type: "String", attribute: "icone" },
9
- sansBordure: { reflect: false, type: "Boolean", attribute: "sans-bordure" },
9
+ positionIcone: { reflect: false, type: "String", attribute: "position-icone" },
10
10
  },
11
11
  }}
12
12
  />
13
13
 
14
14
  <script>import Icone from "./Icone.svelte";
15
15
  export let titre;
16
- export let variante = "tertiaire";
17
- export let taille = "sm";
16
+ export let variante;
17
+ export let taille;
18
18
  export let icone = void 0;
19
- export let sansBordure = false;
19
+ export let positionIcone = "sans";
20
20
  </script>
21
21
 
22
- <button class={`bouton ${variante} ${taille}`} class:sansBordure on:click>
23
- {titre}
24
- {#if icone}
25
- <Icone nom={icone} taille="sm" />
22
+ <button
23
+ class={`bouton ${variante} ${taille} icone-${positionIcone}`}
24
+ on:click
25
+ title={positionIcone === "seule" ? titre : ""}
26
+ >
27
+ {#if (positionIcone === "gauche" || positionIcone === "seule") && icone}
28
+ <Icone nom={icone} taille={taille === "lg" ? "md" : "sm"} />
29
+ {/if}
30
+ {#if positionIcone !== "seule"}
31
+ <span>{titre}</span>
32
+ {/if}
33
+ {#if positionIcone === "droite" && icone}
34
+ <Icone nom={icone} taille={taille === "lg" ? "md" : "sm"} />
26
35
  {/if}
27
36
  </button>
28
37
 
29
- <style>
30
- .bouton {
31
- display: flex;
32
- align-items: center;
33
- gap: 8px;
34
- font-family: Marianne, arial, sans-serif;
35
- cursor: pointer;
36
-
37
- &.tertiaire {
38
- align-items: center;
39
- color: #0d0c21;
40
- text-align: center;
41
- background: white;
42
- border: 1px solid #ddd;
43
- font-size: 0.875rem;
44
- font-style: normal;
45
- font-weight: 500;
46
- line-height: 1.5rem;
47
- border-radius: 4px;
48
-
49
- &.sm {
50
- padding: 4px 12px;
51
- }
52
-
53
- &.sansBordure {
54
- border: none;
55
- }
56
-
57
- &:hover {
58
- background: rgb(0, 0, 0, 4%);
59
- }
60
-
61
- &:active {
62
- background: rgb(0, 0, 0, 8%);
63
- }
64
-
65
- &:focus {
66
- outline: 2px solid #0a76f6;
67
- outline-offset: 2px;
68
- }
69
- }
70
- }
71
- </style>
38
+ <style>.bouton {
39
+ display: flex;
40
+ align-items: center;
41
+ gap: 8px;
42
+ font-family: Marianne, arial, sans-serif;
43
+ cursor: pointer;
44
+ justify-content: center;
45
+ font-style: normal;
46
+ font-weight: 500;
47
+ }
48
+ .bouton:focus {
49
+ outline: 2px solid #0a76f6;
50
+ outline-offset: 2px;
51
+ }
52
+ .bouton.sm {
53
+ padding: 4px 12px;
54
+ font-size: 0.875rem;
55
+ line-height: 1.5rem;
56
+ }
57
+ .bouton.sm.icone-droite {
58
+ padding-right: 8px;
59
+ }
60
+ .bouton.sm.icone-gauche {
61
+ padding-left: 8px;
62
+ }
63
+ .bouton.sm.icone-seule {
64
+ padding: 8px;
65
+ }
66
+ .bouton.md {
67
+ padding: 8px 16px;
68
+ font-size: 1rem;
69
+ line-height: 1.5rem;
70
+ }
71
+ .bouton.md.icone-droite {
72
+ padding-right: 12px;
73
+ }
74
+ .bouton.md.icone-gauche {
75
+ padding-left: 12px;
76
+ }
77
+ .bouton.md.icone-seule {
78
+ padding: 8px;
79
+ }
80
+ .bouton.lg {
81
+ padding: 10px 24px;
82
+ font-size: 1.125rem;
83
+ line-height: 1.75rem;
84
+ }
85
+ .bouton.lg.icone-droite {
86
+ padding-right: 18px;
87
+ }
88
+ .bouton.lg.icone-gauche {
89
+ padding-left: 18px;
90
+ }
91
+ .bouton.lg.icone-seule {
92
+ padding: 12px;
93
+ }
94
+ .bouton.primaire {
95
+ background: var(--bouton-primaire-couleur-fond);
96
+ color: var(--bouton-primaire-couleur-texte);
97
+ border: 1px solid transparent;
98
+ border-radius: var(--bouton-arrondi);
99
+ }
100
+ .bouton.primaire:hover {
101
+ background: var(--bouton-primaire-couleur-fond-survol);
102
+ }
103
+ .bouton.primaire:active {
104
+ background: var(--bouton-primaire-couleur-fond-clique);
105
+ }
106
+ .bouton.tertiaire, .bouton.tertiaire-sans-bordure {
107
+ color: var(--bouton-secondaire-tertiaire-couleur-texte);
108
+ text-align: center;
109
+ background: white;
110
+ border-radius: var(--bouton-arrondi);
111
+ }
112
+ .bouton.tertiaire:hover, .bouton.tertiaire-sans-bordure:hover {
113
+ background: rgba(0, 0, 0, 0.04);
114
+ }
115
+ .bouton.tertiaire:active, .bouton.tertiaire-sans-bordure:active {
116
+ background: rgba(0, 0, 0, 0.08);
117
+ }
118
+ .bouton.tertiaire:focus, .bouton.tertiaire-sans-bordure:focus {
119
+ outline: 2px solid #0a76f6;
120
+ outline-offset: 2px;
121
+ }
122
+ .bouton.tertiaire {
123
+ border: 1px solid #ddd;
124
+ }
125
+ .bouton.tertiaire-sans-bordure {
126
+ border: 1px solid transparent;
127
+ }</style>
@@ -2,10 +2,10 @@ import { SvelteComponent } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  titre: string;
5
- variante?: string;
6
- taille?: string;
5
+ variante: "primaire" | "tertiaire" | "tertiaire-sans-bordure";
6
+ taille: "sm" | "md" | "lg";
7
7
  icone?: string | undefined;
8
- sansBordure?: boolean;
8
+ positionIcone?: "sans" | "seule" | "droite" | "gauche";
9
9
  };
10
10
  events: {
11
11
  click: MouseEvent;
@@ -9,13 +9,16 @@
9
9
  />
10
10
 
11
11
  <script>export let nom;
12
- export let taille = "md";
12
+ export let taille = void 0;
13
13
  </script>
14
14
 
15
15
  <span class="icone fr-icon-{nom} {taille}"></span>
16
16
 
17
17
  <style>.icone {
18
18
  font-family: Marianne, arial, sans-serif;
19
+ --icon-size: 1em;
20
+ line-height: var(--icon-size);
21
+ height: var(--icon-size);
19
22
  }
20
23
  .icone:before {
21
24
  content: "";
@@ -28,13 +31,13 @@ export let taille = "md";
28
31
  width: var(--icon-size);
29
32
  height: var(--icon-size);
30
33
  }
31
- .icone.sm:before {
34
+ .icone.sm {
32
35
  --icon-size: 1rem;
33
36
  }
34
- .icone.md:before {
37
+ .icone.md {
35
38
  --icon-size: 1.5rem;
36
39
  }
37
- .icone.lg:before {
40
+ .icone.lg {
38
41
  --icon-size: 2rem;
39
42
  }
40
43
  .fr-icon-ancient-gate-fill:before {
@@ -2,7 +2,7 @@ import { SvelteComponent } from "svelte";
2
2
  declare const __propDef: {
3
3
  props: {
4
4
  nom: string;
5
- taille?: "sm" | "md" | "lg";
5
+ taille?: "sm" | "md" | "lg" | undefined;
6
6
  };
7
7
  events: {
8
8
  [evt: string]: CustomEvent<any>;
@@ -0,0 +1,239 @@
1
+ <svelte:options
2
+ customElement={{
3
+ tag: "lab-anssi-lien",
4
+ props: {
5
+ titre: { reflect: false, type: "String", attribute: "titre" },
6
+ href: { reflect: false, type: "String", attribute: "href" },
7
+ variante: { reflect: false, type: "String", attribute: "variante" },
8
+ taille: { reflect: false, type: "String", attribute: "taille" },
9
+ icone: { reflect: false, type: "String", attribute: "icone" },
10
+ apparence: { reflect: false, type: "String", attribute: "apparence" },
11
+ cible: { reflect: false, type: "String", attribute: "cible" },
12
+ positionIcone: { reflect: false, type: "String", attribute: "position-icone" },
13
+ },
14
+ }}
15
+ />
16
+
17
+ <script>import Icone from "./Icone.svelte";
18
+ export let titre;
19
+ export let href;
20
+ export let variante;
21
+ export let taille;
22
+ export let icone = void 0;
23
+ export let apparence = "lien";
24
+ export let cible = void 0;
25
+ export let positionIcone = "sans";
26
+ </script>
27
+
28
+ <a
29
+ class={`${variante} ${taille} icone-${positionIcone} ${apparence}`}
30
+ {href}
31
+ target={cible}
32
+ title={positionIcone === "seule" ? titre : ""}
33
+ >
34
+ {#if (positionIcone === "gauche" || positionIcone === "seule") && icone}
35
+ <Icone nom={icone} taille={taille === "lg" ? "md" : "sm"} />
36
+ {/if}
37
+ {#if positionIcone !== "seule"}
38
+ <span>{titre}</span>
39
+ {/if}
40
+ {#if positionIcone === "droite" && icone}
41
+ <Icone nom={icone} taille={taille === "lg" ? "md" : "sm"} />
42
+ {/if}
43
+ {#if cible === "_blank"}
44
+ <Icone nom="external-link-line" />
45
+ {/if}
46
+ </a>
47
+
48
+ <style>.bouton {
49
+ text-decoration: none;
50
+ }
51
+
52
+ .lien-texte {
53
+ font-family: Marianne, arial, sans-serif;
54
+ color: inherit;
55
+ display: inline-flex;
56
+ gap: 2px;
57
+ align-items: center;
58
+ width: fit-content;
59
+ text-decoration: none;
60
+ position: relative;
61
+ }
62
+
63
+ .lien-texte:before {
64
+ content: "";
65
+ position: absolute;
66
+ bottom: 0.2em;
67
+ left: 0;
68
+ width: 100%;
69
+ height: 1px;
70
+ background-color: currentColor;
71
+ }
72
+
73
+ .lien-texte:hover:before {
74
+ bottom: calc(0.2em - 1px);
75
+ height: 2px;
76
+ }
77
+
78
+ .lien {
79
+ font-family: Marianne, arial, sans-serif;
80
+ color: var(--couleur-lien);
81
+ display: inline-flex;
82
+ gap: 8px;
83
+ align-items: center;
84
+ width: fit-content;
85
+ text-decoration: none;
86
+ position: relative;
87
+ }
88
+
89
+ .lien.sm {
90
+ font-size: 0.875rem;
91
+ line-height: 1.5rem;
92
+ }
93
+
94
+ .lien.md {
95
+ font-size: 1rem;
96
+ line-height: 1.5rem;
97
+ }
98
+
99
+ .lien.lg {
100
+ font-size: 1.125rem;
101
+ line-height: 1.75rem;
102
+ }
103
+
104
+ .lien:before {
105
+ content: "";
106
+ position: absolute;
107
+ bottom: 0;
108
+ left: 0;
109
+ width: 100%;
110
+ height: 1px;
111
+ background-color: var(--couleur-lien);
112
+ }
113
+
114
+ .lien:hover:before {
115
+ bottom: -1px;
116
+ height: 2px;
117
+ }
118
+
119
+ .lien:active {
120
+ background: rgba(0, 0, 0, 0.08);
121
+ }
122
+
123
+ .lien:focus {
124
+ outline: 2px solid #0a76f6;
125
+ outline-offset: 2px;
126
+ }
127
+
128
+ .bouton {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ font-family: Marianne, arial, sans-serif;
133
+ cursor: pointer;
134
+ justify-content: center;
135
+ font-style: normal;
136
+ font-weight: 500;
137
+ }
138
+
139
+ .bouton:focus {
140
+ outline: 2px solid #0a76f6;
141
+ outline-offset: 2px;
142
+ }
143
+
144
+ .bouton.sm {
145
+ padding: 4px 12px;
146
+ font-size: 0.875rem;
147
+ line-height: 1.5rem;
148
+ }
149
+
150
+ .bouton.sm.icone-droite {
151
+ padding-right: 8px;
152
+ }
153
+
154
+ .bouton.sm.icone-gauche {
155
+ padding-left: 8px;
156
+ }
157
+
158
+ .bouton.sm.icone-seule {
159
+ padding: 8px;
160
+ }
161
+
162
+ .bouton.md {
163
+ padding: 8px 16px;
164
+ font-size: 1rem;
165
+ line-height: 1.5rem;
166
+ }
167
+
168
+ .bouton.md.icone-droite {
169
+ padding-right: 12px;
170
+ }
171
+
172
+ .bouton.md.icone-gauche {
173
+ padding-left: 12px;
174
+ }
175
+
176
+ .bouton.md.icone-seule {
177
+ padding: 8px;
178
+ }
179
+
180
+ .bouton.lg {
181
+ padding: 10px 24px;
182
+ font-size: 1.125rem;
183
+ line-height: 1.75rem;
184
+ }
185
+
186
+ .bouton.lg.icone-droite {
187
+ padding-right: 18px;
188
+ }
189
+
190
+ .bouton.lg.icone-gauche {
191
+ padding-left: 18px;
192
+ }
193
+
194
+ .bouton.lg.icone-seule {
195
+ padding: 12px;
196
+ }
197
+
198
+ .bouton.primaire {
199
+ background: var(--bouton-primaire-couleur-fond);
200
+ color: var(--bouton-primaire-couleur-texte);
201
+ border: 1px solid transparent;
202
+ border-radius: var(--bouton-arrondi);
203
+ }
204
+
205
+ .bouton.primaire:hover {
206
+ background: var(--bouton-primaire-couleur-fond-survol);
207
+ }
208
+
209
+ .bouton.primaire:active {
210
+ background: var(--bouton-primaire-couleur-fond-clique);
211
+ }
212
+
213
+ .bouton.tertiaire, .bouton.tertiaire-sans-bordure {
214
+ color: var(--bouton-secondaire-tertiaire-couleur-texte);
215
+ text-align: center;
216
+ background: white;
217
+ border-radius: var(--bouton-arrondi);
218
+ }
219
+
220
+ .bouton.tertiaire:hover, .bouton.tertiaire-sans-bordure:hover {
221
+ background: rgba(0, 0, 0, 0.04);
222
+ }
223
+
224
+ .bouton.tertiaire:active, .bouton.tertiaire-sans-bordure:active {
225
+ background: rgba(0, 0, 0, 0.08);
226
+ }
227
+
228
+ .bouton.tertiaire:focus, .bouton.tertiaire-sans-bordure:focus {
229
+ outline: 2px solid #0a76f6;
230
+ outline-offset: 2px;
231
+ }
232
+
233
+ .bouton.tertiaire {
234
+ border: 1px solid #ddd;
235
+ }
236
+
237
+ .bouton.tertiaire-sans-bordure {
238
+ border: 1px solid transparent;
239
+ }</style>
@@ -0,0 +1,25 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ titre: string;
5
+ href: string;
6
+ variante: "primaire" | "tertiaire" | "tertiaire-sans-bordure";
7
+ taille: "sm" | "md" | "lg";
8
+ icone?: string | undefined;
9
+ apparence?: "lien" | "bouton" | "lien-texte";
10
+ cible?: string | undefined;
11
+ positionIcone?: "sans" | "seule" | "droite" | "gauche";
12
+ };
13
+ events: {
14
+ [evt: string]: CustomEvent<any>;
15
+ };
16
+ slots: {};
17
+ exports?: {} | undefined;
18
+ bindings?: string | undefined;
19
+ };
20
+ export type LienProps = typeof __propDef.props;
21
+ export type LienEvents = typeof __propDef.events;
22
+ export type LienSlots = typeof __propDef.slots;
23
+ export default class Lien extends SvelteComponent<LienProps, LienEvents, LienSlots> {
24
+ }
25
+ export {};
@@ -0,0 +1,47 @@
1
+ <svelte:options
2
+ customElement={{
3
+ tag: "lab-anssi-tag",
4
+ props: {
5
+ couleurFond: { reflect: false, type: "String", attribute: "couleur-fond" },
6
+ couleurTexte: { reflect: false, type: "String", attribute: "couleur-texte" },
7
+ label: { reflect: false, type: "String", attribute: "label" },
8
+ taille: { reflect: false, type: "String", attribute: "taille" },
9
+ },
10
+ }}
11
+ />
12
+
13
+ <script>export let label;
14
+ export let couleurTexte;
15
+ export let couleurFond;
16
+ export let taille = "sm";
17
+ </script>
18
+
19
+ <span class="tag {taille}" style:background={couleurFond} style:color={couleurTexte}>
20
+ {label}
21
+ </span>
22
+
23
+ <style>.tag {
24
+ color: var(--tag-couleur-texte);
25
+ background-color: var(--tag-couleur-fond);
26
+ font-family: Marianne;
27
+ font-weight: 400;
28
+ display: inline-block;
29
+ width: fit-content;
30
+ white-space: nowrap;
31
+ max-width: 100%;
32
+ box-sizing: border-box;
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ }
36
+ .tag.sm {
37
+ font-size: 0.75rem;
38
+ line-height: 1.25rem;
39
+ padding: 2px 8px;
40
+ border-radius: 12px;
41
+ }
42
+ .tag.md {
43
+ font-size: 0.875rem;
44
+ line-height: 1.5rem;
45
+ padding: 4px 12px;
46
+ border-radius: 16px;
47
+ }</style>
@@ -1,8 +1,10 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import type { Tag } from "../../types";
3
2
  declare const __propDef: {
4
3
  props: {
5
- tag?: Tag;
4
+ label: string;
5
+ couleurTexte: string | undefined;
6
+ couleurFond: string | undefined;
7
+ taille?: "sm" | "md";
6
8
  };
7
9
  events: {
8
10
  [evt: string]: CustomEvent<any>;