@alveole/storybook 1.9.0 → 2.0.0-alpha
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/BarreDeFiltres.d.ts +20 -0
- package/dist/components/BarreDeFiltres.d.ts.map +1 -0
- package/dist/components/BarreDeFiltres.js +28 -0
- package/dist/components/ColorSwatch.d.ts +10 -0
- package/dist/components/ColorSwatch.d.ts.map +1 -0
- package/dist/components/ColorSwatch.js +37 -0
- package/dist/components/DocFooter.d.ts.map +1 -1
- package/dist/components/DocFooter.js +1 -1
- package/dist/components/EcranDeCatalogue.d.ts +18 -0
- package/dist/components/EcranDeCatalogue.d.ts.map +1 -0
- package/dist/components/EcranDeCatalogue.js +16 -0
- package/dist/components/EnTeteDeFiche.d.ts +10 -0
- package/dist/components/EnTeteDeFiche.d.ts.map +1 -0
- package/dist/components/EnTeteDeFiche.js +13 -0
- package/dist/components/ExampleBlock.d.ts +12 -0
- package/dist/components/ExampleBlock.d.ts.map +1 -0
- package/dist/components/ExampleBlock.js +69 -0
- package/dist/components/ExemplesDeLaStory.d.ts +10 -0
- package/dist/components/ExemplesDeLaStory.d.ts.map +1 -0
- package/dist/components/ExemplesDeLaStory.js +27 -0
- package/dist/components/FiltreDeroulant.d.ts +22 -0
- package/dist/components/FiltreDeroulant.d.ts.map +1 -0
- package/dist/components/FiltreDeroulant.js +10 -0
- package/dist/components/GrilleDeFiches.d.ts +15 -0
- package/dist/components/GrilleDeFiches.d.ts.map +1 -0
- package/dist/components/GrilleDeFiches.js +14 -0
- package/dist/components/MenuCard.d.ts +9 -0
- package/dist/components/MenuCard.d.ts.map +1 -0
- package/dist/components/MenuCard.js +8 -0
- package/dist/components/PageTitle.d.ts +19 -0
- package/dist/components/PageTitle.d.ts.map +1 -0
- package/dist/components/PageTitle.js +16 -0
- package/dist/components/ScreenZone.d.ts +19 -0
- package/dist/components/ScreenZone.d.ts.map +1 -0
- package/dist/components/ScreenZone.js +35 -0
- package/dist/components/StoryCard.d.ts.map +1 -1
- package/dist/components/StoryCard.js +3 -1
- package/dist/components/StoryLayout.d.ts +14 -0
- package/dist/components/StoryLayout.d.ts.map +1 -0
- package/dist/components/StoryLayout.js +21 -0
- package/dist/components/StorySummary.d.ts +7 -0
- package/dist/components/StorySummary.d.ts.map +1 -0
- package/dist/components/StorySummary.js +8 -0
- package/dist/components/UIKitColumn.d.ts +25 -0
- package/dist/components/UIKitColumn.d.ts.map +1 -0
- package/dist/components/UIKitColumn.js +24 -0
- package/dist/components/UIKitTopBar.d.ts +11 -2
- package/dist/components/UIKitTopBar.d.ts.map +1 -1
- package/dist/components/UIKitTopBar.js +84 -27
- package/dist/components/choixDuFiltre.d.ts +14 -0
- package/dist/components/choixDuFiltre.d.ts.map +1 -0
- package/dist/components/choixDuFiltre.js +10 -0
- package/dist/components/hauteurDeCarte.d.ts +6 -0
- package/dist/components/hauteurDeCarte.d.ts.map +1 -0
- package/dist/components/hauteurDeCarte.js +5 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/navigation.d.ts +6 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +3 -0
- package/dist/pages/InstallationPage.d.ts +8 -0
- package/dist/pages/InstallationPage.d.ts.map +1 -0
- package/dist/pages/InstallationPage.js +13 -0
- package/dist/pages/PhilosophyPage.d.ts +2 -1
- package/dist/pages/PhilosophyPage.d.ts.map +1 -1
- package/dist/pages/PhilosophyPage.js +7 -7
- package/dist/pages/UIKitHomePage.d.ts.map +1 -1
- package/dist/pages/UIKitHomePage.js +3 -7
- package/dist/pages/UIKitPage.d.ts +3 -4
- package/dist/pages/UIKitPage.d.ts.map +1 -1
- package/dist/pages/UIKitPage.js +59 -36
- package/dist/pages/UIKitThemePage.d.ts +6 -1
- package/dist/pages/UIKitThemePage.d.ts.map +1 -1
- package/dist/pages/UIKitThemePage.js +4 -8
- package/dist/pages/ecransDuKit.d.ts +18 -0
- package/dist/pages/ecransDuKit.d.ts.map +1 -0
- package/dist/pages/ecransDuKit.js +11 -0
- package/dist/pages/installation.d.ts +18 -0
- package/dist/pages/installation.d.ts.map +1 -0
- package/dist/pages/installation.js +218 -0
- package/dist/pages/installationOutillage.d.ts +7 -0
- package/dist/pages/installationOutillage.d.ts.map +1 -0
- package/dist/pages/installationOutillage.js +152 -0
- package/dist/pages/philosophie.d.ts +10 -0
- package/dist/pages/philosophie.d.ts.map +1 -0
- package/dist/pages/philosophie.js +46 -0
- package/dist/pressePapiers.d.ts +10 -0
- package/dist/pressePapiers.d.ts.map +1 -0
- package/dist/pressePapiers.js +14 -0
- package/dist/screens/StoriesScreen.d.ts +2 -1
- package/dist/screens/StoriesScreen.d.ts.map +1 -1
- package/dist/screens/StoriesScreen.js +18 -35
- package/dist/screens/StoryDetailScreen.d.ts +2 -1
- package/dist/screens/StoryDetailScreen.d.ts.map +1 -1
- package/dist/screens/StoryDetailScreen.js +24 -74
- package/dist/screens/ThemeCSSVariablesScreen.d.ts +2 -1
- package/dist/screens/ThemeCSSVariablesScreen.d.ts.map +1 -1
- package/dist/screens/ThemeCSSVariablesScreen.js +7 -97
- package/dist/screens/ThemeConstantDetailScreen.d.ts +2 -1
- package/dist/screens/ThemeConstantDetailScreen.d.ts.map +1 -1
- package/dist/screens/ThemeConstantDetailScreen.js +4 -4
- package/dist/screens/ThemeConstantsScreen.d.ts +2 -1
- package/dist/screens/ThemeConstantsScreen.d.ts.map +1 -1
- package/dist/screens/ThemeConstantsScreen.js +7 -8
- package/dist/screens/ThemePaletteScreen.d.ts +2 -1
- package/dist/screens/ThemePaletteScreen.d.ts.map +1 -1
- package/dist/screens/ThemePaletteScreen.js +11 -92
- package/dist/screens/ThemeTypographyScreen.d.ts +2 -1
- package/dist/screens/ThemeTypographyScreen.d.ts.map +1 -1
- package/dist/screens/ThemeTypographyScreen.js +6 -6
- package/dist/screens/colonnesDeFiches.d.ts +6 -0
- package/dist/screens/colonnesDeFiches.d.ts.map +1 -0
- package/dist/screens/colonnesDeFiches.js +20 -0
- package/dist/screens/paletteSections.d.ts +30 -0
- package/dist/screens/paletteSections.d.ts.map +1 -0
- package/dist/screens/paletteSections.js +76 -0
- package/dist/screens/sourcesDExemples.d.ts +17 -0
- package/dist/screens/sourcesDExemples.d.ts.map +1 -0
- package/dist/screens/sourcesDExemples.js +27 -0
- package/dist/screens/variablesCSSDuTheme.d.ts +12 -0
- package/dist/screens/variablesCSSDuTheme.d.ts.map +1 -0
- package/dist/screens/variablesCSSDuTheme.js +77 -0
- package/dist/screens/variablesDeTypographie.d.ts +8 -0
- package/dist/screens/variablesDeTypographie.d.ts.map +1 -0
- package/dist/screens/variablesDeTypographie.js +23 -0
- package/dist/storySource.d.ts +7 -0
- package/dist/storySource.d.ts.map +1 -0
- package/dist/storySource.js +7 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +11 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +20 -4
- package/package.json +19 -9
- package/dist/styles.d.ts +0 -7
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js +0 -6
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box,
|
|
3
|
-
import {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
return (_jsx(Card, { onPress: onPress, children: _jsxs(Box, { display: "flex", gap: 8, p: '150', children: [_jsx(Typography, { style: text.Titres['H4 - SM'], children: title }), _jsx(Typography, { style: text['Corps de texte'].SM.Regular, children: description })] }) }));
|
|
7
|
-
};
|
|
8
|
-
export const UIKitThemePage = ({ title = 'UI Kit - Thème', description = 'Tokens du thème', onOpenColors, onOpenTypography, }) => {
|
|
9
|
-
return (_jsx(Page, { scrollable: true, title: title, description: description, children: _jsx(Section, { withPaddingY: true, children: _jsxs(Box, { display: "flex", gap: 16, children: [_jsx(ThemeCard, { title: "Couleurs", description: "Palette et couleurs du th\u00E8me.", onPress: onOpenColors }), _jsx(ThemeCard, { title: "Typographies", description: "Styles de texte et hi\u00E9rarchie typographique.", onPress: onOpenTypography })] }) }) }));
|
|
2
|
+
import { Box, Page, Section } from '@alveole/components';
|
|
3
|
+
import { MenuCard } from '../components/MenuCard';
|
|
4
|
+
export const UIKitThemePage = ({ title = 'UI Kit - Thème', description = 'Tokens du thème', onOpenColors, onOpenTypography, onOpenCSSVariables, sidebar, footerContent, beforeContent, }) => {
|
|
5
|
+
return (_jsx(Page, { scrollable: true, title: title, description: description, sidebar: sidebar, footerContent: footerContent, beforeContent: beforeContent, children: _jsx(Section, { withPaddingY: true, children: _jsxs(Box, { display: "flex", gap: 16, children: [_jsx(MenuCard, { title: "Couleurs", description: "Palette et couleurs du th\u00E8me.", onPress: onOpenColors }), _jsx(MenuCard, { title: "Typographies", description: "Styles de texte et hi\u00E9rarchie typographique.", onPress: onOpenTypography }), onOpenCSSVariables ? (_jsx(MenuCard, { title: "Variables CSS", description: "Les jetons du th\u00E8me expos\u00E9s en variables CSS.", onPress: onOpenCSSVariables })) : null] }) }) }));
|
|
10
6
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BlankPage } from './UIKitPage';
|
|
2
|
+
type InternalHeaderProps = {
|
|
3
|
+
canGoBack: boolean;
|
|
4
|
+
onBack: () => void;
|
|
5
|
+
};
|
|
6
|
+
export declare const InternalHeader: ({ canGoBack, onBack }: InternalHeaderProps) => import("react").JSX.Element | null;
|
|
7
|
+
export declare const HomeScreen: ({ title, description, blankPage, onOpenComponents, onOpenTheme, onOpenConstants, onOpenBlank, onOpenPhilosophy, }: {
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
blankPage?: BlankPage;
|
|
11
|
+
onOpenComponents: () => void;
|
|
12
|
+
onOpenTheme: () => void;
|
|
13
|
+
onOpenConstants: () => void;
|
|
14
|
+
onOpenBlank: () => void;
|
|
15
|
+
onOpenPhilosophy: () => void;
|
|
16
|
+
}) => import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=ecransDuKit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecransDuKit.d.ts","sourceRoot":"","sources":["../../src/pages/ecransDuKit.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM7C,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,uBAAuB,mBAAmB,uCAUxE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,mHASxB;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B,gCAwBA,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Button, Page, Section } from '@alveole/components';
|
|
3
|
+
import { MenuCard } from '../components/MenuCard';
|
|
4
|
+
export const InternalHeader = ({ canGoBack, onBack }) => {
|
|
5
|
+
if (!canGoBack)
|
|
6
|
+
return null;
|
|
7
|
+
return (_jsx(Section, { withPaddingY: true, children: _jsx(Box, { children: _jsx(Button, { title: "Retour", variant: "tertiary", size: "sm", onPress: onBack }) }) }));
|
|
8
|
+
};
|
|
9
|
+
export const HomeScreen = ({ title, description, blankPage, onOpenComponents, onOpenTheme, onOpenConstants, onOpenBlank, onOpenPhilosophy, }) => {
|
|
10
|
+
return (_jsx(Page, { scrollable: true, title: title, description: description, children: _jsx(Section, { withPaddingY: true, children: _jsxs(Box, { display: "flex", gap: 16, children: [_jsx(MenuCard, { title: "Composants", description: "Catalogue des composants et de leurs variantes.", onPress: onOpenComponents }), _jsx(MenuCard, { title: "Th\u00E8me", description: "Couleurs et typographies du design system.", onPress: onOpenTheme }), _jsx(MenuCard, { title: "Constantes", description: "Constantes expos\u00E9es par le th\u00E8me.", onPress: onOpenConstants }), _jsx(MenuCard, { title: "Philosophie", description: "Les principes qui guident Alveole.", onPress: onOpenPhilosophy }), blankPage ? (_jsx(MenuCard, { title: blankPage.title ?? 'Page vierge', description: blankPage.description ?? 'Espace de test libre pour expérimenter.', onPress: onOpenBlank })) : null] }) }) }));
|
|
11
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { HighlightProps } from '@alveole/components';
|
|
2
|
+
/**
|
|
3
|
+
* Le texte de la page Installation. Comme la Philosophie, il est range en donnees : ajouter une
|
|
4
|
+
* etape ne demande pas de toucher au JSX. Chaque etape doit pouvoir etre suivie telle quelle par
|
|
5
|
+
* une personne ou par une IA, donc le code montre est complet et copiable.
|
|
6
|
+
*/
|
|
7
|
+
export type ExtraitDeCode = {
|
|
8
|
+
langage: HighlightProps['language'];
|
|
9
|
+
fichier?: string;
|
|
10
|
+
source: string;
|
|
11
|
+
};
|
|
12
|
+
export type EtapeDInstallation = {
|
|
13
|
+
titre: string;
|
|
14
|
+
paragraphes: readonly string[];
|
|
15
|
+
extraits?: readonly ExtraitDeCode[];
|
|
16
|
+
};
|
|
17
|
+
export declare const ETAPES_D_INSTALLATION: readonly EtapeDInstallation[];
|
|
18
|
+
//# sourceMappingURL=installation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation.d.ts","sourceRoot":"","sources":["../../src/pages/installation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACrC,CAAC;AA4NF,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAA+C,CAAC"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { ETAPES_D_OUTILLAGE } from './installationOutillage';
|
|
2
|
+
const ETAPES_DE_BASE = [
|
|
3
|
+
{
|
|
4
|
+
titre: '1. Prérequis',
|
|
5
|
+
paragraphes: [
|
|
6
|
+
'Alveole s’installe dans une application Expo (Expo Router) qui utilise Tamagui 1.x. Les composants sont rendus sur iOS, Android et web.',
|
|
7
|
+
'Les dépendances natives requises par @alveole/components (expo-router, expo-web-browser, react-native-svg, react-native-safe-area-context, tamagui et les paquets @tamagui/*…) sont déclarées en peerDependencies : les installer avec `npx expo install` pour obtenir les versions compatibles avec le SDK Expo.',
|
|
8
|
+
],
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
titre: '2. Installer les paquets',
|
|
12
|
+
paragraphes: [
|
|
13
|
+
'Tous les paquets @alveole/* doivent avoir exactement le même numéro de version, sans ^ ni ~. Ils sont publiés ensemble et s’appuient les uns sur les autres : mélanger les versions provoque des erreurs de types ou de rendu difficiles à diagnostiquer.',
|
|
14
|
+
'Pour monter de version, changer tous les paquets @alveole/* en même temps, y compris la clé allowScripts.',
|
|
15
|
+
'Le script postinstall de @alveole/components copie pdf.min.mjs et pdf.worker.min.mjs dans public/ : le visualiseur PDF en a besoin sur le web. npm ne l’exécute que s’il est autorisé dans allowScripts, avec le même numéro de version que les paquets.',
|
|
16
|
+
'Ces deux fichiers sont régénérés à chaque installation : les ajouter au .gitignore du projet.',
|
|
17
|
+
],
|
|
18
|
+
extraits: [
|
|
19
|
+
{
|
|
20
|
+
langage: 'bash',
|
|
21
|
+
source: 'npm install --save-exact @alveole/components@1.10.0 @alveole/core@1.10.0 @alveole/storybook@1.10.0 @alveole/theme@1.10.0\nnpm install --save-dev --save-exact @alveole/eslint-config@1.10.0',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
langage: 'json',
|
|
25
|
+
fichier: 'package.json',
|
|
26
|
+
source: `{
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@alveole/components": "1.10.0",
|
|
29
|
+
"@alveole/core": "1.10.0",
|
|
30
|
+
"@alveole/storybook": "1.10.0",
|
|
31
|
+
"@alveole/theme": "1.10.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@alveole/eslint-config": "1.10.0"
|
|
35
|
+
},
|
|
36
|
+
"allowScripts": {
|
|
37
|
+
"@alveole/components@1.10.0": true
|
|
38
|
+
}
|
|
39
|
+
}`,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
langage: 'plaintext',
|
|
43
|
+
fichier: '.gitignore',
|
|
44
|
+
source: '# Copiés par le postinstall de @alveole/components\npublic/pdf.min.mjs\npublic/pdf.worker.min.mjs',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
titre: '3. Configurer ESLint',
|
|
50
|
+
paragraphes: [
|
|
51
|
+
'L’application doit utiliser la configuration ESLint d’Alveole. Elle connaît les conventions des composants et évite les erreurs de lint qu’une configuration maison signalerait à tort. ESLint 9 ou 10 sont acceptés.',
|
|
52
|
+
],
|
|
53
|
+
extraits: [
|
|
54
|
+
{
|
|
55
|
+
langage: 'typescript',
|
|
56
|
+
fichier: 'eslint.config.js',
|
|
57
|
+
source: `const { defineConfig } = require('eslint/config');
|
|
58
|
+
const alveoleConfig = require('@alveole/eslint-config');
|
|
59
|
+
|
|
60
|
+
module.exports = defineConfig([
|
|
61
|
+
...alveoleConfig,
|
|
62
|
+
{
|
|
63
|
+
settings: {
|
|
64
|
+
react: {
|
|
65
|
+
version: '19.2',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
]);`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
titre: '4. Configurer Tamagui',
|
|
75
|
+
paragraphes: [
|
|
76
|
+
'Les composants Alveole reposent sur Tamagui 1.x. L’application déclare sa configuration Tamagui, la référence dans package.json et active le plugin Babel, qui extrait le CSS en production.',
|
|
77
|
+
],
|
|
78
|
+
extraits: [
|
|
79
|
+
{
|
|
80
|
+
langage: 'typescript',
|
|
81
|
+
fichier: 'tamagui.config.ts',
|
|
82
|
+
source: `import { defaultConfig } from '@tamagui/config/v4';
|
|
83
|
+
import { createTamagui } from 'tamagui';
|
|
84
|
+
|
|
85
|
+
const config = createTamagui(defaultConfig);
|
|
86
|
+
|
|
87
|
+
export type Conf = typeof config;
|
|
88
|
+
|
|
89
|
+
declare module 'tamagui' {
|
|
90
|
+
interface TamaguiCustomConfig extends Conf {}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default config;`,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
langage: 'typescript',
|
|
97
|
+
fichier: 'babel.config.js',
|
|
98
|
+
source: `module.exports = function (api) {
|
|
99
|
+
api.cache(() => process.env.NODE_ENV);
|
|
100
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
presets: ['babel-preset-expo'],
|
|
104
|
+
plugins: [
|
|
105
|
+
[
|
|
106
|
+
'@tamagui/babel-plugin',
|
|
107
|
+
{
|
|
108
|
+
components: ['tamagui'],
|
|
109
|
+
config: './tamagui.config.ts',
|
|
110
|
+
disableDebugAttr: isDev,
|
|
111
|
+
disableServerOptimization: isDev,
|
|
112
|
+
...(isDev ? {} : { cssPath: './.tamagui/app.css', emitSingleCSSFile: true }),
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
};`,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
langage: 'json',
|
|
121
|
+
fichier: 'package.json',
|
|
122
|
+
source: `{
|
|
123
|
+
"tamagui": {
|
|
124
|
+
"config": "./tamagui.config.ts"
|
|
125
|
+
}
|
|
126
|
+
}`,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
titre: '5. Brancher le ThemeProvider',
|
|
132
|
+
paragraphes: [
|
|
133
|
+
'ThemeProvider (@alveole/theme) charge les polices et fournit les couleurs et typographies à tous les composants. Il se place à la racine, dans app/_layout.tsx, au-dessus du TamaguiProvider de l’application.',
|
|
134
|
+
'Par défaut, ThemeProvider affiche un indicateur de chargement le temps de charger les polices. Une application qui a son propre splash screen passe loader={false} et masque son splash dans onReady.',
|
|
135
|
+
'Toasts (@alveole/components) est nécessaire pour afficher les notifications ; PageMetaProvider gère les balises <meta> sur le web.',
|
|
136
|
+
],
|
|
137
|
+
extraits: [
|
|
138
|
+
{
|
|
139
|
+
langage: 'tsx',
|
|
140
|
+
fichier: 'app/_layout.tsx',
|
|
141
|
+
source: `import { PageMetaProvider, Toasts } from '@alveole/components';
|
|
142
|
+
import { ThemeProvider } from '@alveole/theme';
|
|
143
|
+
import { Slot } from 'expo-router';
|
|
144
|
+
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
145
|
+
import { TamaguiProvider } from 'tamagui';
|
|
146
|
+
import tamaguiConfig from '../tamagui.config';
|
|
147
|
+
import config from '../alveole.config';
|
|
148
|
+
|
|
149
|
+
export default function RootLayout() {
|
|
150
|
+
return (
|
|
151
|
+
<ThemeProvider color={config.palette}>
|
|
152
|
+
<SafeAreaProvider>
|
|
153
|
+
<TamaguiProvider defaultTheme="light" config={tamaguiConfig}>
|
|
154
|
+
<PageMetaProvider meta={[]}>
|
|
155
|
+
<Toasts>
|
|
156
|
+
<Slot />
|
|
157
|
+
</Toasts>
|
|
158
|
+
</PageMetaProvider>
|
|
159
|
+
</TamaguiProvider>
|
|
160
|
+
</SafeAreaProvider>
|
|
161
|
+
</ThemeProvider>
|
|
162
|
+
);
|
|
163
|
+
}`,
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
titre: '6. Personnaliser les couleurs',
|
|
169
|
+
paragraphes: [
|
|
170
|
+
'Les couleurs se surchargent dans un fichier alveole.config.ts à la racine du projet, importé par le layout et passé au ThemeProvider via la prop color.',
|
|
171
|
+
'La palette est partielle : seules les clés fournies remplacent celles d’Alveole. Les valeurs viennent de préférence des nuanciers exportés par @alveole/theme (Colors.RougeGroseille, Colors.BleuCaptive…) ; la rubrique Thème › Couleurs liste les clés disponibles.',
|
|
172
|
+
'La clé light cible les jetons sémantiques du thème clair (artwork, background, border, text) ; les clés de premier niveau (primary, background.button, stepper…) ciblent les couleurs propres aux composants.',
|
|
173
|
+
],
|
|
174
|
+
extraits: [
|
|
175
|
+
{
|
|
176
|
+
langage: 'typescript',
|
|
177
|
+
fichier: 'alveole.config.ts',
|
|
178
|
+
source: `import { Colors, type DeepPartial, type Palette } from '@alveole/theme';
|
|
179
|
+
|
|
180
|
+
const palette: DeepPartial<Palette> = {
|
|
181
|
+
light: {
|
|
182
|
+
background: {
|
|
183
|
+
'action-high-primary': Colors.RougeGroseille['main-465'],
|
|
184
|
+
'action-high-primary-hover': Colors.RougeGroseille['200'],
|
|
185
|
+
'alt-primary': Colors.RougeGroseille['975'],
|
|
186
|
+
},
|
|
187
|
+
border: {
|
|
188
|
+
'action-high-primary': Colors.RougeGroseille['main-465'],
|
|
189
|
+
},
|
|
190
|
+
text: {
|
|
191
|
+
'title-primary': Colors.RougeGroseille['main-465'],
|
|
192
|
+
'active-primary': Colors.RougeGroseille['main-465'],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
primary: Colors.RougeGroseille['main-465'],
|
|
197
|
+
|
|
198
|
+
background: {
|
|
199
|
+
button: {
|
|
200
|
+
primary: {
|
|
201
|
+
default: Colors.RougeGroseille['main-465'],
|
|
202
|
+
hover: Colors.RougeGroseille['200'],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
stepper: {
|
|
208
|
+
current: Colors.RougeGroseille['625'],
|
|
209
|
+
success: Colors.RougeGroseille['main-465'],
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export default { palette };`,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
];
|
|
218
|
+
export const ETAPES_D_INSTALLATION = [...ETAPES_DE_BASE, ...ETAPES_D_OUTILLAGE];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EtapeDInstallation } from './installation';
|
|
2
|
+
/**
|
|
3
|
+
* Suite de la page Installation : les options (thème dynamique, catalogue) et l'outillage (Jest),
|
|
4
|
+
* puis la vérification. Separees des etapes de base pour garder chaque fichier lisible.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ETAPES_D_OUTILLAGE: readonly EtapeDInstallation[];
|
|
7
|
+
//# sourceMappingURL=installationOutillage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installationOutillage.d.ts","sourceRoot":"","sources":["../../src/pages/installationOutillage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,kBAAkB,EAmJ3D,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Suite de la page Installation : les options (thème dynamique, catalogue) et l'outillage (Jest),
|
|
3
|
+
* puis la vérification. Separees des etapes de base pour garder chaque fichier lisible.
|
|
4
|
+
*/
|
|
5
|
+
export const ETAPES_D_OUTILLAGE = [
|
|
6
|
+
{
|
|
7
|
+
titre: '7. Thème dynamique (facultatif)',
|
|
8
|
+
paragraphes: [
|
|
9
|
+
'Quand les couleurs dépendent de données chargées à l’exécution (une société, un client), fusionner alveole.config avec la palette calculée grâce à deepMerge (@alveole/theme), puis passer le résultat au ThemeProvider. deepMerge ignore les valeurs absentes : une palette partielle ne remplace que ses clés.',
|
|
10
|
+
],
|
|
11
|
+
extraits: [
|
|
12
|
+
{
|
|
13
|
+
langage: 'tsx',
|
|
14
|
+
fichier: 'providers/ClientThemeProvider.tsx',
|
|
15
|
+
source: `import { deepMerge, ThemeProvider, type DeepPartial, type Palette } from '@alveole/theme';
|
|
16
|
+
import React from 'react';
|
|
17
|
+
import config from '../alveole.config';
|
|
18
|
+
|
|
19
|
+
export const ClientThemeProvider = ({
|
|
20
|
+
clientPalette,
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
clientPalette?: DeepPartial<Palette>;
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}) => {
|
|
26
|
+
const color = React.useMemo(() => deepMerge(config.palette, clientPalette), [clientPalette]);
|
|
27
|
+
|
|
28
|
+
return <ThemeProvider color={color}>{children}</ThemeProvider>;
|
|
29
|
+
};`,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
titre: '8. Configurer Jest',
|
|
35
|
+
paragraphes: [
|
|
36
|
+
'@alveole/components et Tamagui sont publiés en ESM et importent des fichiers .css : Jest doit les transformer au lieu de les ignorer, et remplacer les .css par un stub.',
|
|
37
|
+
'Certains modules natifs chargés par les composants (expo-asset pour le favicon de PageHead, matchMedia pour Reanimated) n’existent pas dans l’environnement de test : les simuler dans jest.setup.js.',
|
|
38
|
+
],
|
|
39
|
+
extraits: [
|
|
40
|
+
{
|
|
41
|
+
langage: 'typescript',
|
|
42
|
+
fichier: 'jest.config.js',
|
|
43
|
+
source: `const webPreset = require('jest-expo/web/jest-preset');
|
|
44
|
+
|
|
45
|
+
const [babelModule, babelOptions] = webPreset.transform['\\\\.[jt]sx?$'];
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
...webPreset,
|
|
49
|
+
setupFiles: [...(webPreset.setupFiles ?? []), '<rootDir>/jest.setup.js'],
|
|
50
|
+
moduleNameMapper: {
|
|
51
|
+
...webPreset.moduleNameMapper,
|
|
52
|
+
'\\\\.css$': '<rootDir>/jest.cssStub.js',
|
|
53
|
+
},
|
|
54
|
+
transform: {
|
|
55
|
+
...webPreset.transform,
|
|
56
|
+
'\\\\.[jt]sx?$|\\\\.mjs$': [babelModule, babelOptions],
|
|
57
|
+
},
|
|
58
|
+
// On transforme tout node_modules, sauf les plugins Babel eux-mêmes.
|
|
59
|
+
transformIgnorePatterns: ['/node_modules/react-native-reanimated/plugin/', '/node_modules/@react-native/babel-preset/'],
|
|
60
|
+
};`,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
langage: 'typescript',
|
|
64
|
+
fichier: 'jest.cssStub.js',
|
|
65
|
+
source: 'module.exports = {};',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
langage: 'typescript',
|
|
69
|
+
fichier: 'jest.setup.js',
|
|
70
|
+
source: `jest.mock('expo-asset', () => ({
|
|
71
|
+
Asset: { fromModule: () => ({ uri: 'test-file-stub' }) },
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
if (typeof window !== 'undefined' && !window.matchMedia) {
|
|
75
|
+
window.matchMedia = () => ({
|
|
76
|
+
matches: false,
|
|
77
|
+
media: '',
|
|
78
|
+
onchange: null,
|
|
79
|
+
addListener: () => {},
|
|
80
|
+
removeListener: () => {},
|
|
81
|
+
addEventListener: () => {},
|
|
82
|
+
removeEventListener: () => {},
|
|
83
|
+
dispatchEvent: () => false,
|
|
84
|
+
});
|
|
85
|
+
}`,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
titre: '9. Monter le catalogue dans l’application (facultatif)',
|
|
91
|
+
paragraphes: [
|
|
92
|
+
'@alveole/storybook sert à afficher, dans l’application elle-même, le catalogue des composants Alveole et ceux du projet. Deux routes suffisent : la liste et la fiche d’un composant. Les écrans Couleurs, Typographies et Constantes s’ajoutent de la même façon.',
|
|
93
|
+
'Le catalogue n’a d’intérêt qu’en développement : y donner accès par un bouton affiché sous __DEV__.',
|
|
94
|
+
],
|
|
95
|
+
extraits: [
|
|
96
|
+
{
|
|
97
|
+
langage: 'tsx',
|
|
98
|
+
fichier: 'app/ui-kit/index.tsx',
|
|
99
|
+
source: `import * as AlveoleStories from '@alveole/components/stories';
|
|
100
|
+
import { StoriesScreen, toStoryModules } from '@alveole/storybook';
|
|
101
|
+
|
|
102
|
+
const stories = toStoryModules(AlveoleStories);
|
|
103
|
+
|
|
104
|
+
export default function UIKitIndexScreen() {
|
|
105
|
+
return (
|
|
106
|
+
<StoriesScreen
|
|
107
|
+
stories={stories}
|
|
108
|
+
title="UI Kit - Composants"
|
|
109
|
+
getStoryHref={story => \`/ui-kit/components/\${encodeURIComponent(story.default.title)}\`}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}`,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
langage: 'tsx',
|
|
116
|
+
fichier: 'app/ui-kit/components/[component].tsx',
|
|
117
|
+
source: `import * as AlveoleStories from '@alveole/components/stories';
|
|
118
|
+
import { StoryDetailScreen, findStoryByTitle, toStoryModules } from '@alveole/storybook';
|
|
119
|
+
import { useLocalSearchParams } from 'expo-router';
|
|
120
|
+
|
|
121
|
+
const stories = toStoryModules(AlveoleStories);
|
|
122
|
+
|
|
123
|
+
export default function UIKitComponentScreen() {
|
|
124
|
+
const { component } = useLocalSearchParams<{ component: string }>();
|
|
125
|
+
|
|
126
|
+
return <StoryDetailScreen story={findStoryByTitle(stories, component)} notFoundMessage="Composant introuvable" />;
|
|
127
|
+
}`,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
titre: '10. Vérifier',
|
|
133
|
+
paragraphes: [
|
|
134
|
+
'Afficher un premier composant pour valider l’installation, puis lancer le lint et le typecheck de l’application.',
|
|
135
|
+
],
|
|
136
|
+
extraits: [
|
|
137
|
+
{
|
|
138
|
+
langage: 'tsx',
|
|
139
|
+
fichier: 'app/index.tsx',
|
|
140
|
+
source: `import { Button } from '@alveole/components';
|
|
141
|
+
|
|
142
|
+
export default function Home() {
|
|
143
|
+
return <Button variant="primary" title="Alveole est installé" onPress={() => {}} />;
|
|
144
|
+
}`,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
langage: 'bash',
|
|
148
|
+
source: 'npx eslint .\nnpx tsc --noEmit',
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Le texte de la page Philosophie. Il est range ici, en donnees, parce qu'ecrire une section de
|
|
3
|
+
* plus ne doit pas demander de toucher a du JSX : la page sait rendre, elle n'a pas a savoir quoi.
|
|
4
|
+
*/
|
|
5
|
+
export type SectionDePhilosophie = {
|
|
6
|
+
titre: string;
|
|
7
|
+
paragraphes: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
export declare const SECTIONS_DE_PHILOSOPHIE: readonly SectionDePhilosophie[];
|
|
10
|
+
//# sourceMappingURL=philosophie.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"philosophie.d.ts","sourceRoot":"","sources":["../../src/pages/philosophie.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,SAAS,oBAAoB,EA6ClE,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const SECTIONS_DE_PHILOSOPHIE = [
|
|
2
|
+
{
|
|
3
|
+
titre: 'Objectif',
|
|
4
|
+
paragraphes: [
|
|
5
|
+
"Alveole est un framework de composants conçu pour accélérer la construction d'outils B2B. L'ambition est de proposer une expérience clé en main : installer les packages, utiliser les composants, livrer. Pas de configuration interminable, pas de décisions de design à prendre à chaque écran.",
|
|
6
|
+
],
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
titre: 'Convention plutôt que configuration',
|
|
10
|
+
paragraphes: [
|
|
11
|
+
"Alveole s'inspire du principe Convention over Configuration : le thème par défaut est pensé pour fonctionner sans ajustement. La customisation reste possible — palette, typographie, espacements — mais elle est optionnelle et ciblée. Le but est de ne pas passer du temps à configurer ce qui fonctionne déjà bien.",
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
titre: "Des composants pensés pour l'UX",
|
|
16
|
+
paragraphes: [
|
|
17
|
+
"Chaque composant embarque les meilleures pratiques UI et UX de sa catégorie. L'objectif n'est pas de fournir une brique neutre que chaque projet devra affiner, mais un composant fini qui propose d'emblée la meilleure expérience pour l'utilisateur final. Il ne faut pas réinventer la roue à chaque projet.",
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
titre: 'Des choix assumés',
|
|
22
|
+
paragraphes: [
|
|
23
|
+
"Certaines décisions ne sont pas exposées en configuration. Par exemple, les icônes Lucide utilisent systématiquement un strokeWidth à 1.5 — cette valeur n'est pas modifiable par le consommateur du composant. Ce type de choix garantit la cohérence visuelle de l'ensemble : un design system qui offre trop de flexibilité cesse d'être un design system.",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
titre: "Le catalogue n'est pas une application",
|
|
28
|
+
paragraphes: [
|
|
29
|
+
"Ce site ne titre pas ses pages avec PageHeader, et c'est volontaire. PageHeader est l'en-tête des écrans d'une application cliente : son titre se lit dans le registre d'un outil de travail, à 24. Un site de documentation se lit dans un autre registre, à 40, celui que Primer et Atlassian emploient tous deux pour leur propre documentation.",
|
|
30
|
+
"Les trois références séparent les deux, chacune à sa façon : Primer publie un paquet distinct, @primer/react-brand, pour sa documentation et sa vitrine ; Atlassian titre la sienne avec un style local au site, à une taille qui n'existe dans aucun de ses jetons, leur échelle s'arrêtant à 32 ; Uber reste dans son échelle publiée mais ne livre aucun PageHeader, son site composant son titre directement.",
|
|
31
|
+
"C'est la voie d'Uber qui est suivie ici, parce que c'est celle du design system dont la portée ressemble le plus à la nôtre, natif et web à la fois : une seule échelle de titres, et un site de documentation qui compose son titre avec, sans emprunter un composant d'application. La conséquence pratique : dans une application, un titre de page passe par PageHeader ; nulle part ailleurs.",
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
titre: 'Inspirations',
|
|
36
|
+
paragraphes: [
|
|
37
|
+
"Alveole s'inspire de trois systèmes de design de référence dans l'écosystème B2B et open source : l'Atlassian Design System, reconnu pour sa rigueur dans les outils professionnels, Primer, le design system de GitHub, apprécié pour sa clarté et sa cohérence à grande échelle, et Base, celui d'Uber, dont la portée couvre comme la nôtre le natif et le web.",
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
titre: 'Construit dans la durée par Captive',
|
|
42
|
+
paragraphes: [
|
|
43
|
+
"Alveole est maintenu par Captive et évolue au fil des projets réels. Chaque composant est extrait, généralisé et affiné à partir de besoins concrets. Le framework grandit progressivement, avec une attention constante à la qualité plutôt qu'à l'exhaustivité.",
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copie une valeur, quand le navigateur le permet. Le presse-papiers n'existe pas partout : le
|
|
3
|
+
* catalogue est aussi rendu hors navigateur, et un navigateur peut refuser l'acces. Appeler
|
|
4
|
+
* l'API sans verifier leve une erreur que le gestionnaire d'evenement avale en silence, et la
|
|
5
|
+
* copie echoue alors sans que rien ne le dise.
|
|
6
|
+
*
|
|
7
|
+
* Rend `true` quand la copie a ete lancee, pour que l'appelant n'annonce que ce qui a eu lieu.
|
|
8
|
+
*/
|
|
9
|
+
export declare const copier: (valeur: string, quandCopie: () => void) => boolean;
|
|
10
|
+
//# sourceMappingURL=pressePapiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pressePapiers.d.ts","sourceRoot":"","sources":["../src/pressePapiers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,YAAY,MAAM,IAAI,KAAG,OAM/D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copie une valeur, quand le navigateur le permet. Le presse-papiers n'existe pas partout : le
|
|
3
|
+
* catalogue est aussi rendu hors navigateur, et un navigateur peut refuser l'acces. Appeler
|
|
4
|
+
* l'API sans verifier leve une erreur que le gestionnaire d'evenement avale en silence, et la
|
|
5
|
+
* copie echoue alors sans que rien ne le dise.
|
|
6
|
+
*
|
|
7
|
+
* Rend `true` quand la copie a ete lancee, pour que l'appelant n'annonce que ce qui a eu lieu.
|
|
8
|
+
*/
|
|
9
|
+
export const copier = (valeur, quandCopie) => {
|
|
10
|
+
if (typeof navigator === 'undefined' || !navigator.clipboard)
|
|
11
|
+
return false;
|
|
12
|
+
navigator.clipboard.writeText(valeur).then(quandCopie);
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
@@ -6,10 +6,11 @@ export type StoriesScreenProps = {
|
|
|
6
6
|
description?: string;
|
|
7
7
|
emptyMessage?: string;
|
|
8
8
|
beforeContent?: React.ReactNode;
|
|
9
|
+
sidebar?: React.ReactNode;
|
|
9
10
|
footerContent?: React.ReactNode;
|
|
10
11
|
createLabel?: string;
|
|
11
12
|
onCreatePress?: () => void;
|
|
12
13
|
getStoryHref: (story: StorybookModule) => string;
|
|
13
14
|
};
|
|
14
|
-
export declare const StoriesScreen: ({ stories, title, description, emptyMessage, beforeContent, footerContent, createLabel, onCreatePress, getStoryHref, }: StoriesScreenProps) => React.JSX.Element;
|
|
15
|
+
export declare const StoriesScreen: ({ stories, title, description, emptyMessage, beforeContent, sidebar, footerContent, createLabel, onCreatePress, getStoryHref, }: StoriesScreenProps) => React.JSX.Element;
|
|
15
16
|
//# sourceMappingURL=StoriesScreen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoriesScreen.d.ts","sourceRoot":"","sources":["../../src/screens/StoriesScreen.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"StoriesScreen.d.ts","sourceRoot":"","sources":["../../src/screens/StoriesScreen.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,EAAiB,eAAe,EAAE,MAAM,UAAU,CAAC;AAI1D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,MAAM,CAAC;CAClD,CAAC;AAgBF,eAAO,MAAM,aAAa,GAAI,iIAW3B,kBAAkB,sBAgDpB,CAAC"}
|
|
@@ -1,45 +1,28 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Box, Button, Page, Section } from '@alveole/components';
|
|
3
3
|
import { useTheme } from '@alveole/theme';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { useWindowDimensions } from 'react-native';
|
|
6
|
+
import { BarreDeFiltres } from '../components/BarreDeFiltres';
|
|
7
|
+
import { GrilleDeFiches } from '../components/GrilleDeFiches';
|
|
8
|
+
import { PageTitle } from '../components/PageTitle';
|
|
9
|
+
import { ScreenZone } from '../components/ScreenZone';
|
|
9
10
|
import { filterStories, getAllStoryTags, groupStoriesByTag } from '../utils';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
import { largeurDeColonne } from './colonnesDeFiches';
|
|
12
|
+
/** L'action de creation n'a de sens qu'avec un libelle et une action : un seul des deux donnerait
|
|
13
|
+
* un bouton muet ou inerte. */
|
|
14
|
+
const ActionDeCreation = ({ label, onPress }) => {
|
|
15
|
+
if (!label || !onPress)
|
|
16
|
+
return null;
|
|
17
|
+
return (_jsx(Section, { withPaddingY: true, children: _jsx(Box, { style: { alignItems: 'flex-end' }, children: _jsx(Button, { title: label, variant: "primary", onPress: onPress }) }) }));
|
|
18
|
+
};
|
|
19
|
+
export const StoriesScreen = ({ stories, title = 'UI Kit - Components', description = 'Shared component catalog', emptyMessage = 'No story found.', beforeContent, sidebar, footerContent, createLabel, onCreatePress, getStoryHref, }) => {
|
|
20
|
+
const { grilles } = useTheme();
|
|
19
21
|
const { width } = useWindowDimensions();
|
|
20
|
-
const columns = width >= 1200 ? 3 : width >= 768 ? 2 : 1;
|
|
21
|
-
const columnStyle = columns === 1
|
|
22
|
-
? { width: '100%' }
|
|
23
|
-
: columns === 2
|
|
24
|
-
? { width: 'calc((100% - 16px) / 2)' }
|
|
25
|
-
: { width: 'calc((100% - 32px) / 3)' };
|
|
26
22
|
const [query, setQuery] = React.useState('');
|
|
27
23
|
const [selectedTag, setSelectedTag] = React.useState(null);
|
|
28
24
|
const [selectedFlag, setSelectedFlag] = React.useState(null);
|
|
29
|
-
const [openFilter, setOpenFilter] = React.useState(null);
|
|
30
25
|
const allTags = React.useMemo(() => getAllStoryTags(stories), [stories]);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
query,
|
|
34
|
-
selectedTag,
|
|
35
|
-
selectedFlag,
|
|
36
|
-
}), [stories, query, selectedTag, selectedFlag]);
|
|
37
|
-
const groupedStories = React.useMemo(() => groupStoriesByTag(filteredStories, allTags), [filteredStories, allTags]);
|
|
38
|
-
return (_jsxs(Page, { scrollable: true, title: title, description: description, beforeContent: _jsxs(_Fragment, { children: [beforeContent, createLabel && onCreatePress ? (_jsx(Section, { withPaddingY: true, children: _jsx(Box, { style: { alignItems: 'flex-end' }, children: _jsx(Button, { title: createLabel, variant: "primary", onPress: onCreatePress }) }) })) : null] }), children: [_jsxs(Box, { ...screenContent, children: [_jsx(Section, { withPaddingY: false, children: _jsx(PageHeader, { title: title }) }), _jsx(Section, { withPaddingY: false, children: _jsxs(ScrollView, { horizontal: true, nestedScrollEnabled: true, directionalLockEnabled: Platform.OS === 'ios', showsHorizontalScrollIndicator: false, contentContainerStyle: { flexDirection: 'row', gap: 8, alignItems: 'center' }, children: [_jsx(Box, { style: { minWidth: 200 }, children: _jsx(SearchField, { placeholder: "Button, Tabs, Card...", value: query, onChangeText: setQuery, size: "sm" }) }), _jsx(ActionMenu, { placement: "bottom-start", scrollable: false, open: openFilter === 'tags', setOpen: open => setOpenFilter(open ? 'tags' : null), renderTrigger: () => (_jsx(Button, { variant: "secondary", title: selectedTag ?? 'Tags', endIcon: "ChevronDown", size: "sm", selected: selectedTag !== null, active: openFilter === 'tags' })), children: allTags.map(tag => (_jsx(ActionMenu.Item, { title: tag, selected: selectedTag === tag, onPress: () => {
|
|
39
|
-
setSelectedTag(prev => (prev === tag ? null : tag));
|
|
40
|
-
setOpenFilter(null);
|
|
41
|
-
} }, tag))) }), _jsx(ActionMenu, { placement: "bottom-start", scrollable: false, open: openFilter === 'indicateurs', setOpen: open => setOpenFilter(open ? 'indicateurs' : null), renderTrigger: () => (_jsx(Button, { variant: "secondary", title: AVAILABLE_FLAGS.find(f => f.key === selectedFlag)?.label ?? 'Indicateurs', endIcon: "ChevronDown", size: "sm", selected: selectedFlag !== null, active: openFilter === 'indicateurs' })), children: AVAILABLE_FLAGS.map(flag => (_jsx(ActionMenu.Item, { title: flag.label, selected: selectedFlag === flag.key, onPress: () => {
|
|
42
|
-
setSelectedFlag(prev => (prev === flag.key ? null : flag.key));
|
|
43
|
-
setOpenFilter(null);
|
|
44
|
-
} }, flag.key))) })] }) }), groupedStories.length === 0 ? (_jsx(Section, { withPaddingY: false, children: _jsx(Typography, { style: text['Corps de texte'].MD.Regular, children: emptyMessage }) })) : (groupedStories.map(([tag, taggedStories]) => (_jsx(Section, { withPaddingY: false, children: _jsxs(Box, { display: "flex", gap: 16, children: [_jsx(Typography, { style: text.Titres['H4 - SM'], children: tag }), _jsx(Box, { display: "flex", flexDirection: "row", flexWrap: "wrap", gap: 16, children: taggedStories.map(story => (_jsx(Box, { style: { alignSelf: 'stretch', width: columnStyle.width }, children: _jsx(StoryCard, { story: story, href: getStoryHref(story) }) }, story.default.title))) })] }) }, tag))))] }), footerContent] }));
|
|
26
|
+
const groupedStories = React.useMemo(() => groupStoriesByTag(filterStories({ stories, query, selectedTag, selectedFlag }), allTags), [stories, query, selectedTag, selectedFlag, allTags]);
|
|
27
|
+
return (_jsxs(Page, { scrollable: true, title: title, description: description, sidebar: sidebar, beforeContent: _jsxs(_Fragment, { children: [beforeContent, _jsx(ActionDeCreation, { label: createLabel, onPress: onCreatePress })] }), children: [_jsxs(ScreenZone, { largeur: grilles['12 colonnes'], children: [_jsx(PageTitle, { title: title }), _jsx(BarreDeFiltres, { recherche: query, onRecherche: setQuery, tags: allTags, tagChoisi: selectedTag, onTag: setSelectedTag, indicateurChoisi: selectedFlag, onIndicateur: setSelectedFlag }), _jsx(GrilleDeFiches, { groupes: groupedStories, largeurDeFiche: largeurDeColonne(width), getStoryHref: getStoryHref, messageVide: emptyMessage })] }), footerContent] }));
|
|
45
28
|
};
|