@ouestfrance/sipa-bms-ui 8.20.0 → 8.22.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/dist/components/feedback/BmsGhost.vue.d.ts +24 -0
- package/dist/components/form/BmsAutocomplete.vue.d.ts +2 -2
- package/dist/components/form/BmsFilePicker.vue.d.ts +4 -0
- package/dist/components/form/BmsMultiSelect.vue.d.ts +4 -0
- package/dist/components/form/BmsServerAutocomplete.vue.d.ts +2 -2
- package/dist/components/form/RawAutocomplete.vue.d.ts +11 -3
- package/dist/components/layout/BmsFloatingWindow.vue.d.ts +20 -1
- package/dist/index.d.ts +2 -1
- package/dist/mockServiceWorker.js +1 -1
- package/dist/sipa-bms-ui.css +117 -393
- package/dist/sipa-bms-ui.es.js +447 -129
- package/dist/sipa-bms-ui.es.js.map +1 -1
- package/dist/sipa-bms-ui.umd.js +449 -130
- package/dist/sipa-bms-ui.umd.js.map +1 -1
- package/package.json +12 -12
- package/src/assets/scss/_conf.scss +0 -1
- package/src/assets/scss/app.scss +0 -1
- package/src/components/button/BmsAllButtons.stories.js +50 -23
- package/src/components/button/BmsButton.stories.js +153 -59
- package/src/components/feedback/BmsGhost.stories.js +60 -0
- package/src/components/feedback/BmsGhost.vue +82 -0
- package/src/components/feedback/BmsTooltip.vue +15 -1
- package/src/components/feedback/UiTooltip.vue +9 -1
- package/src/components/form/BmsFilePicker.stories.js +6 -1
- package/src/components/form/BmsFilePicker.vue +10 -5
- package/src/components/form/BmsMultiSelect.vue +32 -25
- package/src/components/form/BmsSelect.vue +18 -16
- package/src/components/form/RawAutocomplete.vue +16 -4
- package/src/components/form/RawInputText.vue +1 -0
- package/src/components/layout/BmsFloatingWindow.stories.js +226 -12
- package/src/components/layout/BmsFloatingWindow.vue +286 -13
- package/src/components/layout/BmsModal.stories.js +2 -1
- package/src/components/layout/BmsSplitWindow.vue +0 -1
- package/src/components/table/BmsTableFilters.vue +1 -1
- package/src/documentation/button/primaryButton.mdx +142 -0
- package/src/documentation/{secondaryButton.mdx → button/secondaryButton.mdx} +2 -2
- package/src/documentation/foundation/contributing.mdx +72 -0
- package/src/documentation/foundation/gettingstarted.mdx +7 -0
- package/src/documentation/{principles.mdx → foundation/principles.mdx} +9 -9
- package/src/documentation/icons.mdx +43 -0
- package/src/index.ts +3 -0
- package/src/showroom/pages/forms.vue +10 -1
- package/src/assets/scss/_formkit.scss +0 -353
- package/src/components/form/Form.stories.js +0 -35
- package/src/documentation/primaryButton.mdx +0 -20
- /package/src/documentation/{button.mdx → button/button.mdx} +0 -0
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="floating-window-wrapper">
|
|
3
|
-
<div
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<div ref="wrapperRef" class="floating-window-wrapper">
|
|
3
|
+
<div
|
|
4
|
+
v-if="isDragging"
|
|
5
|
+
class="floating-window__drag-overlay"
|
|
6
|
+
@mousemove="onDrag"
|
|
7
|
+
@mouseup="onDragEnd"
|
|
8
|
+
/>
|
|
9
|
+
<div
|
|
10
|
+
ref="windowRef"
|
|
11
|
+
class="floating-window"
|
|
12
|
+
:class="{
|
|
13
|
+
'floating-window--expanded': isExpanded,
|
|
14
|
+
'floating-window--dragging': isDragging,
|
|
15
|
+
}"
|
|
16
|
+
v-show="open"
|
|
17
|
+
:style="windowStyle"
|
|
18
|
+
>
|
|
19
|
+
<div class="floating-window__header" @mousedown="onDragStart">
|
|
20
|
+
<h3 class="floating-window__header__title">{{ title }}</h3>
|
|
6
21
|
<div class="floating-window__header__buttons">
|
|
7
|
-
<BmsIconButton
|
|
8
|
-
|
|
22
|
+
<BmsIconButton
|
|
23
|
+
v-if="expandable"
|
|
24
|
+
class="floating-window__expand-btn"
|
|
25
|
+
:class="{ 'floating-window__expand-btn--expanded': isExpanded }"
|
|
26
|
+
:tooltip-text="
|
|
27
|
+
isExpanded ? 'Réduire la fenêtre' : 'Maximiser la fenêtre'
|
|
28
|
+
"
|
|
29
|
+
@click.prevent.stop="toggleExpand"
|
|
30
|
+
>
|
|
31
|
+
<Minimize2 v-if="isExpanded" />
|
|
32
|
+
<Maximize2 v-else />
|
|
9
33
|
</BmsIconButton>
|
|
10
34
|
<BmsIconButton @click.prevent.stop="open = false">
|
|
11
35
|
<X />
|
|
@@ -20,14 +44,223 @@
|
|
|
20
44
|
</template>
|
|
21
45
|
|
|
22
46
|
<script setup lang="ts">
|
|
23
|
-
import { Maximize2, X } from 'lucide-vue-next';
|
|
47
|
+
import { Maximize2, Minimize2, X } from 'lucide-vue-next';
|
|
24
48
|
import BmsIconButton from '../button/BmsIconButton.vue';
|
|
49
|
+
import { ref, computed, onMounted, watch, type CSSProperties } from 'vue';
|
|
25
50
|
|
|
26
|
-
|
|
51
|
+
export type Placement =
|
|
52
|
+
| 'top-left'
|
|
53
|
+
| 'top-right'
|
|
54
|
+
| 'bottom-left'
|
|
55
|
+
| 'bottom-right'
|
|
56
|
+
| 'center';
|
|
57
|
+
|
|
58
|
+
const props = withDefaults(
|
|
59
|
+
defineProps<{
|
|
60
|
+
title: string;
|
|
61
|
+
defaultPlacement?: Placement;
|
|
62
|
+
expandable?: boolean;
|
|
63
|
+
expandedWidth?: string;
|
|
64
|
+
expandedHeight?: string;
|
|
65
|
+
expandTarget?: string;
|
|
66
|
+
width?: string;
|
|
67
|
+
height?: string;
|
|
68
|
+
}>(),
|
|
69
|
+
{
|
|
70
|
+
defaultPlacement: 'center',
|
|
71
|
+
expandable: false,
|
|
72
|
+
expandedWidth: '100%',
|
|
73
|
+
expandedHeight: '100%',
|
|
74
|
+
expandTarget: undefined,
|
|
75
|
+
width: '50%',
|
|
76
|
+
height: '40%',
|
|
77
|
+
},
|
|
78
|
+
);
|
|
27
79
|
|
|
28
80
|
const open = defineModel<boolean>({
|
|
29
81
|
default: false,
|
|
30
82
|
});
|
|
83
|
+
|
|
84
|
+
const wrapperRef = ref<HTMLElement | null>(null);
|
|
85
|
+
const windowRef = ref<HTMLElement | null>(null);
|
|
86
|
+
const position = ref<{ x: number; y: number } | null>(null);
|
|
87
|
+
const computedSize = ref<{ width: number; height: number } | null>(null);
|
|
88
|
+
const isDragging = ref(false);
|
|
89
|
+
const dragOffset = ref({ x: 0, y: 0 });
|
|
90
|
+
const isExpanded = ref(false);
|
|
91
|
+
const positionBeforeExpand = ref<{ x: number; y: number } | null>(null);
|
|
92
|
+
const expandedStyle = ref<CSSProperties | null>(null);
|
|
93
|
+
|
|
94
|
+
function computeInitialPosition(): { x: number; y: number } | null {
|
|
95
|
+
if (!wrapperRef.value || !windowRef.value) return null;
|
|
96
|
+
|
|
97
|
+
const wrapperRect = wrapperRef.value.getBoundingClientRect();
|
|
98
|
+
const windowRect = windowRef.value.getBoundingClientRect();
|
|
99
|
+
const padding = 16;
|
|
100
|
+
|
|
101
|
+
switch (props.defaultPlacement) {
|
|
102
|
+
case 'top-left':
|
|
103
|
+
return { x: wrapperRect.left + padding, y: wrapperRect.top + padding };
|
|
104
|
+
case 'top-right':
|
|
105
|
+
return {
|
|
106
|
+
x: wrapperRect.right - windowRect.width - padding,
|
|
107
|
+
y: wrapperRect.top + padding,
|
|
108
|
+
};
|
|
109
|
+
case 'bottom-left':
|
|
110
|
+
return {
|
|
111
|
+
x: wrapperRect.left + padding,
|
|
112
|
+
y: wrapperRect.bottom - windowRect.height - padding,
|
|
113
|
+
};
|
|
114
|
+
case 'bottom-right':
|
|
115
|
+
return {
|
|
116
|
+
x: wrapperRect.right - windowRect.width - padding,
|
|
117
|
+
y: wrapperRect.bottom - windowRect.height - padding,
|
|
118
|
+
};
|
|
119
|
+
case 'center':
|
|
120
|
+
default:
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function initPosition() {
|
|
126
|
+
if (props.defaultPlacement !== 'center' && !position.value) {
|
|
127
|
+
position.value = computeInitialPosition();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
onMounted(() => {
|
|
132
|
+
if (open.value) {
|
|
133
|
+
initPosition();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
watch(open, (newVal) => {
|
|
138
|
+
if (newVal) {
|
|
139
|
+
requestAnimationFrame(initPosition);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const windowStyle = computed<CSSProperties>(() => {
|
|
144
|
+
if (isExpanded.value && expandedStyle.value) {
|
|
145
|
+
return expandedStyle.value;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const sizeStyle: CSSProperties = {};
|
|
149
|
+
if (computedSize.value) {
|
|
150
|
+
sizeStyle.width = `${computedSize.value.width}px`;
|
|
151
|
+
sizeStyle.height = `${computedSize.value.height}px`;
|
|
152
|
+
} else {
|
|
153
|
+
if (props.width) {
|
|
154
|
+
sizeStyle.width = props.width;
|
|
155
|
+
}
|
|
156
|
+
if (props.height) {
|
|
157
|
+
sizeStyle.height = props.height;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!position.value) {
|
|
162
|
+
return sizeStyle;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
position: 'absolute',
|
|
167
|
+
left: `${position.value.x}px`,
|
|
168
|
+
top: `${position.value.y}px`,
|
|
169
|
+
...sizeStyle,
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
function computeExpandedStyle(): CSSProperties {
|
|
174
|
+
if (props.expandTarget) {
|
|
175
|
+
const targetEl = document.querySelector(props.expandTarget);
|
|
176
|
+
if (targetEl) {
|
|
177
|
+
const targetRect = targetEl.getBoundingClientRect();
|
|
178
|
+
return {
|
|
179
|
+
position: 'fixed',
|
|
180
|
+
left: `${targetRect.left}px`,
|
|
181
|
+
top: `${targetRect.top}px`,
|
|
182
|
+
width:
|
|
183
|
+
props.expandedWidth === '100%'
|
|
184
|
+
? `${targetRect.width}px`
|
|
185
|
+
: props.expandedWidth,
|
|
186
|
+
height:
|
|
187
|
+
props.expandedHeight === '100%'
|
|
188
|
+
? `${targetRect.height}px`
|
|
189
|
+
: props.expandedHeight,
|
|
190
|
+
maxWidth: 'none',
|
|
191
|
+
maxHeight: 'none',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
position: 'absolute',
|
|
198
|
+
width: props.expandedWidth,
|
|
199
|
+
height: props.expandedHeight,
|
|
200
|
+
maxWidth: 'none',
|
|
201
|
+
maxHeight: 'none',
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function toggleExpand() {
|
|
206
|
+
if (isExpanded.value) {
|
|
207
|
+
expandedStyle.value = null;
|
|
208
|
+
position.value = positionBeforeExpand.value;
|
|
209
|
+
isExpanded.value = false;
|
|
210
|
+
} else {
|
|
211
|
+
positionBeforeExpand.value = position.value;
|
|
212
|
+
expandedStyle.value = computeExpandedStyle();
|
|
213
|
+
isExpanded.value = true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function onDragStart(event: MouseEvent) {
|
|
218
|
+
if (
|
|
219
|
+
(event.target as HTMLElement).closest('.floating-window__header__buttons')
|
|
220
|
+
) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (isExpanded.value) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
isDragging.value = true;
|
|
229
|
+
|
|
230
|
+
if (windowRef.value) {
|
|
231
|
+
const rect = windowRef.value.getBoundingClientRect();
|
|
232
|
+
dragOffset.value = {
|
|
233
|
+
x: event.clientX - rect.left,
|
|
234
|
+
y: event.clientY - rect.top,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
if (!computedSize.value) {
|
|
238
|
+
computedSize.value = { width: rect.width, height: rect.height };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!position.value) {
|
|
242
|
+
position.value = { x: rect.left, y: rect.top };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
document.addEventListener('mousemove', onDrag);
|
|
247
|
+
document.addEventListener('mouseup', onDragEnd);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function onDrag(event: MouseEvent) {
|
|
251
|
+
if (!isDragging.value) return;
|
|
252
|
+
|
|
253
|
+
position.value = {
|
|
254
|
+
x: event.clientX - dragOffset.value.x,
|
|
255
|
+
y: event.clientY - dragOffset.value.y,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function onDragEnd() {
|
|
260
|
+
isDragging.value = false;
|
|
261
|
+
document.removeEventListener('mousemove', onDrag);
|
|
262
|
+
document.removeEventListener('mouseup', onDragEnd);
|
|
263
|
+
}
|
|
31
264
|
</script>
|
|
32
265
|
|
|
33
266
|
<style scoped lang="scss">
|
|
@@ -45,25 +278,65 @@ const open = defineModel<boolean>({
|
|
|
45
278
|
align-items: center;
|
|
46
279
|
pointer-events: none;
|
|
47
280
|
|
|
281
|
+
.floating-window__drag-overlay {
|
|
282
|
+
position: fixed;
|
|
283
|
+
top: 0;
|
|
284
|
+
left: 0;
|
|
285
|
+
width: 100vw;
|
|
286
|
+
height: 100vh;
|
|
287
|
+
z-index: var(--bms-z-index-modal);
|
|
288
|
+
pointer-events: all;
|
|
289
|
+
cursor: grabbing;
|
|
290
|
+
}
|
|
291
|
+
|
|
48
292
|
.floating-window {
|
|
49
293
|
background-color: var(--bms-white);
|
|
50
|
-
height: 100%;
|
|
51
|
-
width: 100%;
|
|
52
294
|
border-radius: var(--bms-border-radius-large);
|
|
53
295
|
border: 1px solid var(--bms-grey-10);
|
|
54
296
|
pointer-events: all;
|
|
55
297
|
display: grid;
|
|
56
298
|
grid-template-rows: auto 1fr;
|
|
57
|
-
box-shadow:
|
|
299
|
+
box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.25);
|
|
58
300
|
z-index: var(--bms-z-index-modal);
|
|
301
|
+
transition:
|
|
302
|
+
left 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
303
|
+
top 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
304
|
+
width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
305
|
+
height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
306
|
+
border-radius 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
307
|
+
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
308
|
+
|
|
309
|
+
&--expanded {
|
|
310
|
+
border-radius: 0;
|
|
311
|
+
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
|
312
|
+
|
|
313
|
+
.floating-window__header {
|
|
314
|
+
cursor: default;
|
|
315
|
+
|
|
316
|
+
&:active {
|
|
317
|
+
cursor: default;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
&--dragging {
|
|
323
|
+
transition: none;
|
|
324
|
+
}
|
|
59
325
|
|
|
60
326
|
&__header {
|
|
61
327
|
display: flex;
|
|
62
328
|
justify-content: space-between;
|
|
63
329
|
align-items: center;
|
|
64
330
|
border-bottom: 1px solid var(--bms-grey-10);
|
|
65
|
-
padding:
|
|
66
|
-
|
|
331
|
+
padding: 0.5em;
|
|
332
|
+
cursor: grab;
|
|
333
|
+
user-select: none;
|
|
334
|
+
|
|
335
|
+
&:active {
|
|
336
|
+
cursor: grabbing;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
&__title {
|
|
67
340
|
margin: 0;
|
|
68
341
|
}
|
|
69
342
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import BmsModal from '@/components/layout/BmsModal.vue';
|
|
2
|
+
import BmsProblem from '@/components/utils/BmsProblem.vue';
|
|
3
|
+
import { isProblem } from '@/helpers/problem.helper.ts';
|
|
2
4
|
import { StatusType } from '@/models/status-type.model';
|
|
3
|
-
import { BmsProblem, isProblem } from '../../index';
|
|
4
5
|
|
|
5
6
|
const openNotification = {
|
|
6
7
|
details: 'this is a detail',
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import {
|
|
3
|
+
Playground,
|
|
4
|
+
DoSimple,
|
|
5
|
+
DoDanger,
|
|
6
|
+
DoSmall,
|
|
7
|
+
DoIconStart,
|
|
8
|
+
DoIconEnd,
|
|
9
|
+
DoSubmit,
|
|
10
|
+
DontLongLabel,
|
|
11
|
+
DoShortLabel,
|
|
12
|
+
DontMultiplePrimary,
|
|
13
|
+
DoOnePrimary,
|
|
14
|
+
DontTooManyIcons,
|
|
15
|
+
DoOneIcon,
|
|
16
|
+
DontGenericLabel,
|
|
17
|
+
DoSpecificLabel,
|
|
18
|
+
DontPrimaryForCancel,
|
|
19
|
+
DoPrimaryForSave,
|
|
20
|
+
} from '../../components/button/BmsButton.stories.js';
|
|
21
|
+
|
|
22
|
+
<Meta title="Documentation/Buttons/Primary" />
|
|
23
|
+
|
|
24
|
+
# <img src="./BmsIcon.png" /> Primary Button
|
|
25
|
+
|
|
26
|
+
The primary button should represent the main action on a screen. There should only be one primary button on an interface. If multiple actions are possible, it is essential to create a hierarchy of actions and use a primary and several secondary or tertiary buttons.
|
|
27
|
+
|
|
28
|
+
## Anatomy
|
|
29
|
+
|
|
30
|
+
Buttons allow users to perform an action or to navigate to another page. They have multiple styles for various needs, and are ideal for calling attention to where a user needs to do something in order to move forward in a flow.
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
## Component
|
|
35
|
+
|
|
36
|
+
Use the controls below to interact with the component and see how it behaves with different configurations.
|
|
37
|
+
|
|
38
|
+
<Canvas of={Playground} />
|
|
39
|
+
|
|
40
|
+
### Props
|
|
41
|
+
|
|
42
|
+
<Controls of={Playground} />
|
|
43
|
+
|
|
44
|
+
## Usage Examples
|
|
45
|
+
|
|
46
|
+
### ✅ Do: Simple action button
|
|
47
|
+
|
|
48
|
+
Use a clear, concise label (maximum 3 words) for the primary action.
|
|
49
|
+
|
|
50
|
+
<Canvas of={DoSimple} />
|
|
51
|
+
|
|
52
|
+
### ✅ Do: Button with icon at start
|
|
53
|
+
|
|
54
|
+
Icons can help clarify the action. Place them at the start of the button.
|
|
55
|
+
|
|
56
|
+
<Canvas of={DoIconStart} />
|
|
57
|
+
|
|
58
|
+
### ✅ Do: Button with icon at end
|
|
59
|
+
|
|
60
|
+
Place icons at the end for navigation or forward actions.
|
|
61
|
+
|
|
62
|
+
<Canvas of={DoIconEnd} />
|
|
63
|
+
|
|
64
|
+
### ✅ Do: Submit button
|
|
65
|
+
|
|
66
|
+
Use `submit` prop for form submissions.
|
|
67
|
+
|
|
68
|
+
<Canvas of={DoSubmit} />
|
|
69
|
+
|
|
70
|
+
### ✅ Do: Danger mode
|
|
71
|
+
|
|
72
|
+
Use danger mode for destructive actions that require caution.
|
|
73
|
+
|
|
74
|
+
<Canvas of={DoDanger} />
|
|
75
|
+
|
|
76
|
+
### ✅ Do: Small variant
|
|
77
|
+
|
|
78
|
+
Use the small variant when space is limited.
|
|
79
|
+
|
|
80
|
+
<Canvas of={DoSmall} />
|
|
81
|
+
|
|
82
|
+
## Rules
|
|
83
|
+
|
|
84
|
+
### ⛔ Don't: Long labels
|
|
85
|
+
|
|
86
|
+
Avoid long labels that exceed 3 words. Keep button text concise and action-oriented.
|
|
87
|
+
|
|
88
|
+
**❌ Don't:**
|
|
89
|
+
|
|
90
|
+
<Canvas of={DontLongLabel} />
|
|
91
|
+
|
|
92
|
+
**✅ Do:**
|
|
93
|
+
|
|
94
|
+
<Canvas of={DoShortLabel} />
|
|
95
|
+
|
|
96
|
+
### ⛔ Don't: Multiple primary buttons
|
|
97
|
+
|
|
98
|
+
Never use multiple primary buttons on the same screen. Use only one primary button per interface.
|
|
99
|
+
|
|
100
|
+
**❌ Don't:**
|
|
101
|
+
|
|
102
|
+
<Canvas of={DontMultiplePrimary} />
|
|
103
|
+
|
|
104
|
+
**✅ Do:**
|
|
105
|
+
|
|
106
|
+
<Canvas of={DoOnePrimary} />
|
|
107
|
+
|
|
108
|
+
### ⛔ Don't: Overuse of icons
|
|
109
|
+
|
|
110
|
+
Don't overload buttons with multiple icons or decorative elements that don't add value.
|
|
111
|
+
|
|
112
|
+
**❌ Don't:**
|
|
113
|
+
|
|
114
|
+
<Canvas of={DontTooManyIcons} />
|
|
115
|
+
|
|
116
|
+
**✅ Do:**
|
|
117
|
+
|
|
118
|
+
<Canvas of={DoOneIcon} />
|
|
119
|
+
|
|
120
|
+
### ⛔ Don't: Generic labels
|
|
121
|
+
|
|
122
|
+
Avoid generic labels like "Click here" or "Submit". Use specific action verbs.
|
|
123
|
+
|
|
124
|
+
**❌ Don't:**
|
|
125
|
+
|
|
126
|
+
<Canvas of={DontGenericLabel} />
|
|
127
|
+
|
|
128
|
+
**✅ Do:**
|
|
129
|
+
|
|
130
|
+
<Canvas of={DoSpecificLabel} />
|
|
131
|
+
|
|
132
|
+
### ⛔ Don't: Primary for secondary actions
|
|
133
|
+
|
|
134
|
+
Don't use primary buttons for secondary or cancel actions. Reserve primary buttons for the main action.
|
|
135
|
+
|
|
136
|
+
**❌ Don't:**
|
|
137
|
+
|
|
138
|
+
<Canvas of={DontPrimaryForCancel} />
|
|
139
|
+
|
|
140
|
+
**✅ Do:**
|
|
141
|
+
|
|
142
|
+
<Canvas of={DoPrimaryForSave} />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import Button from '
|
|
2
|
+
import Button from '../../components/button/BmsButton.vue';
|
|
3
3
|
|
|
4
|
-
<Meta title="Documentation/Buttons/Secondary
|
|
4
|
+
<Meta title="Documentation/Buttons/Secondary" />
|
|
5
5
|
|
|
6
6
|
# <img src="./BmsIcon.png" /> Secondary Button
|
|
7
7
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Foundation/Contributing" />
|
|
4
|
+
|
|
5
|
+
# <img src="./BmsIcon.png" /> Contributing
|
|
6
|
+
|
|
7
|
+
We welcome contributions from the community! To keep the codebase healthy and consistent, please follow the process outlined below before submitting a Merge Request (MR).
|
|
8
|
+
|
|
9
|
+
## Contribution – Challenging the Need for Evolution
|
|
10
|
+
|
|
11
|
+
> **Before adding or modifying a component, question the underlying need.**
|
|
12
|
+
> In a design system every change propagates across many products, so it’s crucial to ensure that new work truly adds value.
|
|
13
|
+
|
|
14
|
+
1. **Define the problem** – Who experiences the pain point? What user goal does it affect?
|
|
15
|
+
2. **Consider existing solutions** – Can the issue be solved with a variant, a token adjustment, or a composition of existing components?
|
|
16
|
+
3. **Evaluate impact** – Think about bundle size, visual consistency, accessibility, and maintenance overhead.
|
|
17
|
+
|
|
18
|
+
Applying this disciplined approach helps the design system stay lean, cohesive, and future‑proof while preventing unnecessary churn.
|
|
19
|
+
|
|
20
|
+
## 1️ Discuss the Change First
|
|
21
|
+
|
|
22
|
+
Before you start coding, **open a thread** on Teams describing the problem you want to solve or the feature you’d like to add. Include:
|
|
23
|
+
|
|
24
|
+
- A clear description of the motivation.
|
|
25
|
+
- Any relevant design sketches or screenshot.
|
|
26
|
+
- Links to related tickets or upstream discussions.
|
|
27
|
+
|
|
28
|
+
This early conversation helps us:
|
|
29
|
+
|
|
30
|
+
- Validate that the change aligns with the project roadmap.
|
|
31
|
+
- Identify potential design conflicts early.
|
|
32
|
+
- Agree on an implementation approach.
|
|
33
|
+
|
|
34
|
+
Only after we give a **“Go‑ahead”** comment should you begin work on the MR.
|
|
35
|
+
|
|
36
|
+
## 2️ Follow Our Development Standards
|
|
37
|
+
|
|
38
|
+
Your contribution must meet the project's quality expectations:
|
|
39
|
+
|
|
40
|
+
(WIP)
|
|
41
|
+
|
|
42
|
+
If any of these checks fail, the MR will be returned for revision.
|
|
43
|
+
|
|
44
|
+
## 3️ Submit Your Merge Request
|
|
45
|
+
|
|
46
|
+
When the feature is complete:
|
|
47
|
+
|
|
48
|
+
1. (WIP)
|
|
49
|
+
|
|
50
|
+
## 4️ Review Process
|
|
51
|
+
|
|
52
|
+
- **Automated checks**: CI will automatically reject the MR if linting, tests, or build steps fail.
|
|
53
|
+
- **Human review**: At least one core maintainer will review the code. They may request changes, ask clarifying questions, or suggest improvements.
|
|
54
|
+
- **Approval**: Once all reviewers approve and CI passes, the MR will be merged.
|
|
55
|
+
|
|
56
|
+
> **We reserve the right to reject any MR** that does not meet our development standards, conflicts with the project direction, or introduces regressions. Rejections will be accompanied by constructive feedback so you can adjust and resubmit.
|
|
57
|
+
|
|
58
|
+
## 5️ Post‑Merge Checklist
|
|
59
|
+
|
|
60
|
+
- Verify that the change appears in the next release notes.
|
|
61
|
+
- Close the associated issue (or move it to _Done_).
|
|
62
|
+
- Celebrate 🎉 – you’ve contributed to the project!
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Additional Tips (Optional)
|
|
67
|
+
|
|
68
|
+
- **Keep PRs small** – aim for a single logical change per MR.
|
|
69
|
+
- **Write clear commit messages** – follow the Conventional Commits format (`feat: add …`, `fix: resolve …`).
|
|
70
|
+
- **Respect the Code of Conduct** – treat all contributors with respect and professionalism.
|
|
71
|
+
|
|
72
|
+
Thank you for helping make this project better! 🙏
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Foundation/Getting started" />
|
|
4
|
+
|
|
5
|
+
# <img src="./BmsIcon.png" /> Getting started
|
|
6
|
+
|
|
7
|
+
All the information are located in the Read Me on [Gitlab](https://gitlab.ouest-france.fr/sipa-ouest-france/platform/platform-library-vuejs-bms)
|
|
@@ -2,7 +2,7 @@ import { Meta } from '@storybook/addon-docs/blocks';
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
<Meta title="
|
|
5
|
+
<Meta title="Foundation/Principles" />
|
|
6
6
|
|
|
7
7
|
# <img src="./BmsIcon.png" /> Principles
|
|
8
8
|
|
|
@@ -16,13 +16,13 @@ bms UI focuses on the essentials, we concentrate on what is useful for interface
|
|
|
16
16
|
|
|
17
17
|
A constraint-based design system is designed to offer a consistent user experience across all products that use it. By limiting possible interpretations, this type of design system provides a clear and consistent logic that facilitates understanding and use of the products. Constraints can be applied to visual elements such as colors, typography, and font sizes, as well as interactive elements such as buttons and menus. By using a constraint-based design system, users can interact with products with confidence, knowing that the design elements will be consistent and predictable.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Documentation of the **bms UI** Design System
|
|
20
20
|
|
|
21
21
|
> **Mission** – Provide a **single Design System** dedicated to the Sipa group’s Back‑Office tools, limiting the use of the Vue framework and offering a constraint‑driven approach to interface design and construction. Goal: reduce costs, ensure visual and functional consistency, and simplify maintenance.
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
-
### 1
|
|
25
|
+
### 1️ Context & Objectives
|
|
26
26
|
|
|
27
27
|
- **Who?**
|
|
28
28
|
The bms UI Design System is actually maintained by the frontend team of **bms**.
|
|
@@ -35,7 +35,7 @@ A constraint-based design system is designed to offer a consistent user experien
|
|
|
35
35
|
- **Target audience**
|
|
36
36
|
Front‑end developers, designers, QA engineers, project managers, and anyone involved in creating or maintaining Back‑Office interfaces.
|
|
37
37
|
|
|
38
|
-
### 2
|
|
38
|
+
### 2️ Core Principles
|
|
39
39
|
|
|
40
40
|
#### 2.1 Focused – Essentials First
|
|
41
41
|
|
|
@@ -59,19 +59,19 @@ A constraint-based design system is designed to offer a consistent user experien
|
|
|
59
59
|
|
|
60
60
|
These constraints are **declarative** – they’re baked directly into components (e.g., `mode="danger"` to have a red button), preventing stylistic drift.
|
|
61
61
|
|
|
62
|
-
### 3
|
|
62
|
+
### 3️ Project Architecture
|
|
63
63
|
|
|
64
64
|
- **Single export** – `import BmsButton from '../components/button/BmsButton.vue';`
|
|
65
65
|
- **Integrated Storybook** – Each component has a `*.stories.js` file showcasing the UI and the props & slots for each component.```
|
|
66
66
|
- **Typescript components** - Each component as typed props & events, and the relevant types are exported by the library (e.g. TableHeader, Caption, etc.)
|
|
67
67
|
|
|
68
|
-
### 4
|
|
68
|
+
### 4️ Usage Guide
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Installation
|
|
71
71
|
|
|
72
72
|
Gitlab documentation https://gitlab.ouest-france.fr/sipa-ouest-france/platform/platform-library-vuejs-bms#installation
|
|
73
73
|
|
|
74
|
-
### 5
|
|
74
|
+
### 5️ Quick FAQ
|
|
75
75
|
|
|
76
76
|
- **Can I add a custom color?**
|
|
77
77
|
**Answer:** No – all colors must come from the defined palette. If a legitimate need arises, open a **Jira** ticket.
|
|
@@ -82,7 +82,7 @@ Gitlab documentation https://gitlab.ouest-france.fr/sipa-ouest-france/platform/p
|
|
|
82
82
|
- **Does the design system support dark mode?**
|
|
83
83
|
**Answer:** No – theming is not available at this time.
|
|
84
84
|
|
|
85
|
-
### 6
|
|
85
|
+
### 6️ Contact & Support
|
|
86
86
|
|
|
87
87
|
- **Teams**: [#🎨bmsUI](https://teams.microsoft.com/l/channel/19%3Au9dPXr-JjoRoaLat-EyS-QEKit1ZzUwQ7G0VrzvDkTE1%40thread.tacv2/%F0%9F%8E%A8bmsUI?groupId=677fd2f9-de86-4bf9-a00c-71817f033ad3&tenantId=a59e9cc9-4ed4-43c4-9f1e-ca78d44b0072&ngc=true&allowXTenantAccess=)
|
|
88
88
|
- **Issues**: [#Jira] (⚠️ WIP)
|