@hgdc/ui 0.6.0 → 0.8.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 +12 -10
- package/dist/access-request.d.ts +50 -0
- package/dist/access-request.js +84 -0
- package/dist/products.d.ts +14 -2
- package/dist/products.js +16 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,16 +39,16 @@ Primitives déjà là : `avatar` `badge` `button` `dialog` `drawer` `dropdown-me
|
|
|
39
39
|
|
|
40
40
|
## Coque des consoles
|
|
41
41
|
|
|
42
|
-
| Import | Exemple
|
|
43
|
-
| -------------- |
|
|
44
|
-
| `app-shell` | `<AppShell sidebarHeader={<OrgSwitcher …/>} nav={<SidebarNav label="Projet">…</SidebarNav>} sidebarFooter={<AccountMenu …/>}>`
|
|
45
|
-
| | `<SidebarNavItem icon={Rocket01Icon} label="Déploiements" render={<Link to="/deployments" />} />`
|
|
46
|
-
| `org-switcher` | `<OrgSwitcher organizations={orgs} activeId={org.id} onSelect={go} createHref="/organisations/nouvelle" />`
|
|
47
|
-
| `account-menu` | `<AccountMenu user={user} onProfile={…} onSecurity={…} onSignOut={signOut} product="Mail" />` : Account et les produits ouverts du catalogue, Mail coché
|
|
48
|
-
| `command-menu` | `<CommandMenu groups={[{ label: "Aller à", items }, { label: "Créer", items }, { label: "Changer", items }]} />` (`Ctrl+K`), `<CommandMenuButton compact="mobile" …/>`
|
|
49
|
-
| `products` | `HGDC_PRODUCTS` (mot, nom, sous-domaine, phrase, icône, état), `HGDC_ACCOUNT`, `productMenuEntries({ current: "Mail" })`
|
|
50
|
-
| `kbd` | `<KbdGroup><Kbd>Ctrl</Kbd><Kbd>K</Kbd></KbdGroup>`
|
|
51
|
-
| `page-header` | `<PageHeader title="Domaines" breadcrumbs={[{ label: "Acme", render: <Link to="/o/acme" /> }, { label: "Domaines" }]} actions={<Button>Ajouter</Button>} />`
|
|
42
|
+
| Import | Exemple |
|
|
43
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `app-shell` | `<AppShell sidebarHeader={<OrgSwitcher …/>} nav={<SidebarNav label="Projet">…</SidebarNav>} sidebarFooter={<AccountMenu …/>}>` |
|
|
45
|
+
| | `<SidebarNavItem icon={Rocket01Icon} label="Déploiements" render={<Link to="/deployments" />} />` |
|
|
46
|
+
| `org-switcher` | `<OrgSwitcher organizations={orgs} activeId={org.id} onSelect={go} createHref="/organisations/nouvelle" />` |
|
|
47
|
+
| `account-menu` | `<AccountMenu user={user} onProfile={…} onSecurity={…} onSignOut={signOut} product="Mail" />` : Account et les produits ouverts du catalogue, Mail coché |
|
|
48
|
+
| `command-menu` | `<CommandMenu groups={[{ label: "Aller à", items }, { label: "Créer", items }, { label: "Changer", items }]} />` (`Ctrl+K`), `<CommandMenuButton compact="mobile" …/>` |
|
|
49
|
+
| `products` | `HGDC_PRODUCTS` (mot, nom, sous-domaine, phrase, icône, état, `entryHref`), `HGDC_ACCOUNT`, `productMenuEntries({ current: "Mail" })` : chaque produit du menu pointe vers son entrée `/auth/hgdc` (ADR 0010) |
|
|
50
|
+
| `kbd` | `<KbdGroup><Kbd>Ctrl</Kbd><Kbd>K</Kbd></KbdGroup>` |
|
|
51
|
+
| `page-header` | `<PageHeader title="Domaines" breadcrumbs={[{ label: "Acme", render: <Link to="/o/acme" /> }, { label: "Domaines" }]} actions={<Button>Ajouter</Button>} />` |
|
|
52
52
|
|
|
53
53
|
La barre se réduit en rail (`Ctrl+B`, mémorisé) : poser `sidebarInitScript` dans le `<head>`. Le kit ne connaît ni routeur ni authentification : liens par `render={<Link />}`, actions par callbacks. Rôles d'organisation : `owner`, `admin`, `member` (Propriétaire, Admin, Membre).
|
|
54
54
|
|
|
@@ -99,6 +99,8 @@ Filtres, tri et page vivent dans l'URL du produit : les composants sont contrôl
|
|
|
99
99
|
| `money-field` | `<MoneyField value={centimes} onChange={…} />` : CHF en centimes, « 1’250.50 », accepte « 12.– » ; `formatChf`, `parseMoney` |
|
|
100
100
|
| `address-fields` | `<AddressFields value={address} onChange={…} errors={validatePostalAddress(address)} />` : rue, numéro, NPA, localité, pays (facture QR) |
|
|
101
101
|
|
|
102
|
+
`access-request` : `<AccessRequest endpoint="https://<deploiement>.convex.site/f/<id>" product="HGDC Mail" signInRender={<Link to="/sign-in" />} />`, la page « Demander un accès » d'un produit (les comptes HGDC s'ouvrent sur invitation). Poste en JSON vers un formulaire HGDC Mail Forms : prénom, nom, entreprise, e-mail professionnel, message facultatif, `produit` caché, piège `_gotcha`. États envoi, réussite, erreur, champ refusé ; `submitAccessRequest` s'appelle seul.
|
|
103
|
+
|
|
102
104
|
Les champs de date sont ceux du navigateur, sans calendrier maison (ADR 0006). Les fonctions pures (`parseMoney`, `contrastRatio`, `validatePostalAddress`, `formatDateRange`) s'importent seules, côté serveur aussi.
|
|
103
105
|
|
|
104
106
|
## Contrôles et surfaces flottantes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Demander un accès à un produit de la famille, sans compte : les comptes HGDC s'ouvrent sur
|
|
4
|
+
* invitation. Le formulaire poste en JSON vers un formulaire HGDC Mail Forms (`POST /f/<id>`,
|
|
5
|
+
* réponse `{ ok }` ou `{ ok: false, error: { code }, errors }`) ; l'équipe reçoit l'avis et
|
|
6
|
+
* invite depuis HGDC Account. Le texte est au tutoiement, comme les pages publiques de la famille.
|
|
7
|
+
*/
|
|
8
|
+
export type AccessRequestValues = {
|
|
9
|
+
prenom: string;
|
|
10
|
+
nom: string;
|
|
11
|
+
entreprise: string;
|
|
12
|
+
email: string;
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const EMPTY_ACCESS_REQUEST: AccessRequestValues;
|
|
16
|
+
/** Ce qu'il faut de `fetch` : une adresse et une requête. */
|
|
17
|
+
export type AccessRequestFetcher = (url: string, init: RequestInit) => Promise<Response>;
|
|
18
|
+
export type AccessRequestResult = {
|
|
19
|
+
kind: "sent";
|
|
20
|
+
} | {
|
|
21
|
+
kind: "invalid";
|
|
22
|
+
errors: Record<string, string>;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "failed";
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Envoie la demande et traduit la réponse. Fonction pure à part du composant : un produit peut
|
|
29
|
+
* l'appeler depuis son propre formulaire. `trap` est le piège à robots (`_gotcha`), vide pour un humain.
|
|
30
|
+
*/
|
|
31
|
+
export declare function submitAccessRequest(endpoint: string, values: AccessRequestValues, product: string, { trap, fetcher }?: {
|
|
32
|
+
trap?: string;
|
|
33
|
+
fetcher?: AccessRequestFetcher;
|
|
34
|
+
}): Promise<AccessRequestResult>;
|
|
35
|
+
export declare function AccessRequest({ endpoint, product, title, description, messageLabel, signInHref, signInRender, homeHref, homeRender, fetcher, }: {
|
|
36
|
+
/** Adresse d'envoi du formulaire Forms : `https://<deploiement>.convex.site/f/<id>`. */
|
|
37
|
+
endpoint: string;
|
|
38
|
+
/** Nom affiché et valeur du champ caché `produit` : « HGDC Mail ». */
|
|
39
|
+
product: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
description?: ReactNode;
|
|
42
|
+
messageLabel?: string;
|
|
43
|
+
signInHref?: string;
|
|
44
|
+
/** Lien du routeur du produit vers la connexion : `signInRender={<Link to="/sign-in" />}`. */
|
|
45
|
+
signInRender?: ReactElement;
|
|
46
|
+
homeHref?: string;
|
|
47
|
+
homeRender?: ReactElement;
|
|
48
|
+
/** Pour les tests. */
|
|
49
|
+
fetcher?: AccessRequestFetcher;
|
|
50
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
4
|
+
import CheckmarkCircle02Icon from "@hugeicons/core-free-icons/CheckmarkCircle02Icon";
|
|
5
|
+
import { HugeiconsIcon } from "@hugeicons/react";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { Alert } from "./alert.js";
|
|
8
|
+
import { Button, buttonVariants } from "./button.js";
|
|
9
|
+
import { Field, FieldError, FieldLabel } from "./field.js";
|
|
10
|
+
import { Input } from "./input.js";
|
|
11
|
+
import { Textarea } from "./textarea.js";
|
|
12
|
+
export const EMPTY_ACCESS_REQUEST = { prenom: "", nom: "", entreprise: "", email: "", message: "" };
|
|
13
|
+
/** Les refus de l'endpoint, dits au tutoiement. */
|
|
14
|
+
const FAILURES = {
|
|
15
|
+
rate_limited: "Trop d'envois en peu de temps. Réessaie dans une minute.",
|
|
16
|
+
origin_not_allowed: "Ce formulaire ne s'envoie que depuis le site de HGDC.",
|
|
17
|
+
form_closed: "Les demandes d'accès sont fermées pour le moment. Réessaie plus tard.",
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Envoie la demande et traduit la réponse. Fonction pure à part du composant : un produit peut
|
|
21
|
+
* l'appeler depuis son propre formulaire. `trap` est le piège à robots (`_gotcha`), vide pour un humain.
|
|
22
|
+
*/
|
|
23
|
+
export async function submitAccessRequest(endpoint, values, product, { trap = "", fetcher = (url, init) => fetch(url, init) } = {}) {
|
|
24
|
+
let result;
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetcher(endpoint, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
29
|
+
body: JSON.stringify({ ...values, produit: product, _gotcha: trap }),
|
|
30
|
+
});
|
|
31
|
+
result = (await response.json());
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return { kind: "failed", message: "Impossible d'envoyer la demande. Vérifie ta connexion et réessaie." };
|
|
35
|
+
}
|
|
36
|
+
if (result.ok)
|
|
37
|
+
return { kind: "sent" };
|
|
38
|
+
if (result.errors && Object.keys(result.errors).length)
|
|
39
|
+
return { kind: "invalid", errors: result.errors };
|
|
40
|
+
return {
|
|
41
|
+
kind: "failed",
|
|
42
|
+
message: FAILURES[result.error?.code ?? ""] ?? "La demande n'est pas partie. Réessaie dans un instant.",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function LinkSlot({ href, render, className, children, }) {
|
|
46
|
+
return useRender({
|
|
47
|
+
defaultTagName: "a",
|
|
48
|
+
render,
|
|
49
|
+
props: mergeProps({ className, children }, render ? {} : { href }),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function AccessRequest({ endpoint, product, title = `Demander un accès à ${product}`, description = "Les comptes HGDC s'ouvrent sur invitation. Dis-nous qui tu es : on te répond rapidement et, si c'est bon, tu reçois une invitation par e-mail.", messageLabel = "Ton projet, en quelques mots (facultatif)", signInHref = "/sign-in", signInRender, homeHref = "/", homeRender, fetcher, }) {
|
|
53
|
+
const [values, setValues] = useState(EMPTY_ACCESS_REQUEST);
|
|
54
|
+
const [trap, setTrap] = useState("");
|
|
55
|
+
const [pending, setPending] = useState(false);
|
|
56
|
+
const [fieldErrors, setFieldErrors] = useState({});
|
|
57
|
+
const [failure, setFailure] = useState(null);
|
|
58
|
+
const [sentTo, setSentTo] = useState(null);
|
|
59
|
+
const set = (key) => (event) => {
|
|
60
|
+
setValues((current) => ({ ...current, [key]: event.target.value }));
|
|
61
|
+
setFieldErrors(({ [key]: _gone, ...rest }) => rest);
|
|
62
|
+
};
|
|
63
|
+
async function submit(event) {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
setPending(true);
|
|
66
|
+
setFailure(null);
|
|
67
|
+
setFieldErrors({});
|
|
68
|
+
const result = await submitAccessRequest(endpoint, values, product, { trap, ...(fetcher ? { fetcher } : {}) });
|
|
69
|
+
if (result.kind === "sent")
|
|
70
|
+
setSentTo(values.email.trim());
|
|
71
|
+
else if (result.kind === "invalid")
|
|
72
|
+
setFieldErrors(result.errors);
|
|
73
|
+
else
|
|
74
|
+
setFailure(result.message);
|
|
75
|
+
setPending(false);
|
|
76
|
+
}
|
|
77
|
+
if (sentTo) {
|
|
78
|
+
return (_jsxs("div", { "data-slot": "access-request", className: "grid rise gap-6", children: [_jsx(HugeiconsIcon, { icon: CheckmarkCircle02Icon, className: "size-10 pop-in text-status-active" }), _jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-semibold text-balance", children: "Demande envoy\u00E9e" }), _jsxs("p", { className: "mt-2 text-muted-foreground", children: ["Merci. Un accus\u00E9 de r\u00E9ception part vers ", sentTo, ". Si ta demande est accept\u00E9e, tu re\u00E7ois une invitation de HGDC Account pour cr\u00E9er ton compte."] })] }), _jsx(LinkSlot, { href: homeHref, render: homeRender, className: buttonVariants({ variant: "outline", size: "lg" }), children: "Retour \u00E0 l'accueil" })] }, "access-done"));
|
|
79
|
+
}
|
|
80
|
+
const invalid = (key) => (fieldErrors[key] ? true : undefined);
|
|
81
|
+
const field = (key, label, input) => (_jsxs(Field, { "data-invalid": invalid(key), children: [_jsx(FieldLabel, { htmlFor: `acces-${key}`, children: label }), input, fieldErrors[key] ? _jsx(FieldError, { children: fieldErrors[key] }) : null] }));
|
|
82
|
+
const text = (key, autoComplete, max, type = "text") => (_jsx(Input, { id: `acces-${key}`, type: type, autoComplete: autoComplete, required: true, maxLength: max, value: values[key], onChange: set(key), "aria-invalid": invalid(key) }));
|
|
83
|
+
return (_jsxs("form", { "data-slot": "access-request", onSubmit: submit, className: "grid rise gap-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-semibold text-balance", children: title }), description ? _jsx("p", { className: "mt-2 text-muted-foreground", children: description }) : null] }), failure ? (_jsx(Alert, { tone: "destructive", role: "alert", children: failure })) : null, _jsxs("div", { className: "grid gap-4", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [field("prenom", "Prénom", text("prenom", "given-name", 100)), field("nom", "Nom", text("nom", "family-name", 100))] }), field("entreprise", "Entreprise", text("entreprise", "organization", 120)), field("email", "E-mail professionnel", text("email", "email", 320, "email")), field("message", messageLabel, _jsx(Textarea, { id: "acces-message", rows: 3, maxLength: 2000, value: values.message, onChange: set("message"), "aria-invalid": invalid("message") })), _jsx("input", { type: "text", name: "_gotcha", tabIndex: -1, autoComplete: "off", "aria-hidden": "true", value: trap, onChange: (e) => setTrap(e.target.value), className: "absolute -left-[9999px] size-px opacity-0" })] }), _jsx(Button, { type: "submit", size: "lg", isLoading: pending, children: "Envoyer la demande" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["D\u00E9j\u00E0 un compte HGDC ?", " ", _jsx(LinkSlot, { href: signInHref, render: signInRender, className: "font-medium text-foreground underline-offset-4 hover:underline", children: "Se connecter" })] })] }, "access"));
|
|
84
|
+
}
|
package/dist/products.d.ts
CHANGED
|
@@ -11,7 +11,13 @@ export type HgdcCatalogProduct = {
|
|
|
11
11
|
name: string;
|
|
12
12
|
/** « host.hgdc.ch ». */
|
|
13
13
|
subdomain: string;
|
|
14
|
+
/** Page d'accueil publique : `https://host.hgdc.ch`. */
|
|
14
15
|
href: string;
|
|
16
|
+
/**
|
|
17
|
+
* Entrée dans l'app avec la session HGDC Account (`PRODUCT_ENTRY_PATH`), sans page d'accueil
|
|
18
|
+
* ni bouton de connexion. Pour Account, sa racine.
|
|
19
|
+
*/
|
|
20
|
+
entryHref: string;
|
|
15
21
|
/** Une phrase, au tutoiement. */
|
|
16
22
|
pitch: string;
|
|
17
23
|
icon: IconSvgElement;
|
|
@@ -22,7 +28,12 @@ export type HgdcCatalogProduct = {
|
|
|
22
28
|
*/
|
|
23
29
|
accent?: EmailAccent | undefined;
|
|
24
30
|
};
|
|
25
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Chemin de l'entrée commune des produits, le `HGDC_ENTRY_PATH` de `@hgdc/auth` : chaque produit
|
|
33
|
+
* le monte (`createHgdcEntry`). Il ouvre l'app avec la session HGDC Account, sans formulaire
|
|
34
|
+
* quand cette session existe.
|
|
35
|
+
*/
|
|
36
|
+
export declare const PRODUCT_ENTRY_PATH = "/auth/hgdc";
|
|
26
37
|
export declare const HGDC_ACCOUNT: HgdcCatalogProduct;
|
|
27
38
|
/** Les produits de la famille, dans leur ordre d'affichage. Account n'en fait pas partie (`HGDC_ACCOUNT`). */
|
|
28
39
|
export declare const HGDC_PRODUCTS: ReadonlyArray<HgdcCatalogProduct>;
|
|
@@ -41,7 +52,8 @@ export type ProductMenuEntry = {
|
|
|
41
52
|
/**
|
|
42
53
|
* Les entrées du menu du compte : Account d'abord, puis les produits ouverts. `current` est le
|
|
43
54
|
* mot du produit affiché (« Mail ») : il est coché. `accountHref` remplace l'adresse d'Account
|
|
44
|
-
* (un Account local en développement).
|
|
55
|
+
* (un Account local en développement). Chaque produit pointe vers son entrée (`entryHref`) :
|
|
56
|
+
* un clic ouvre l'app avec la session HGDC, pas la page d'accueil publique.
|
|
45
57
|
*/
|
|
46
58
|
export declare function productMenuEntries(options?: {
|
|
47
59
|
current?: string | undefined;
|
package/dist/products.js
CHANGED
|
@@ -11,13 +11,21 @@ export const PRODUCT_STAGE_LABEL = {
|
|
|
11
11
|
preview: "Préversion",
|
|
12
12
|
soon: "Bientôt",
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Chemin de l'entrée commune des produits, le `HGDC_ENTRY_PATH` de `@hgdc/auth` : chaque produit
|
|
16
|
+
* le monte (`createHgdcEntry`). Il ouvre l'app avec la session HGDC Account, sans formulaire
|
|
17
|
+
* quand cette session existe.
|
|
18
|
+
*/
|
|
19
|
+
export const PRODUCT_ENTRY_PATH = "/auth/hgdc";
|
|
14
20
|
function product(word, pitch, icon, stage) {
|
|
15
21
|
const subdomain = `${word.toLowerCase()}.hgdc.ch`;
|
|
22
|
+
const href = `https://${subdomain}`;
|
|
16
23
|
return {
|
|
17
24
|
word,
|
|
18
25
|
name: `HGDC ${word}`,
|
|
19
26
|
subdomain,
|
|
20
|
-
href
|
|
27
|
+
href,
|
|
28
|
+
entryHref: `${href}${PRODUCT_ENTRY_PATH}`,
|
|
21
29
|
pitch,
|
|
22
30
|
icon,
|
|
23
31
|
stage,
|
|
@@ -25,7 +33,8 @@ function product(word, pitch, icon, stage) {
|
|
|
25
33
|
};
|
|
26
34
|
}
|
|
27
35
|
/** HGDC Account : le compte commun (profil, sécurité, organisations), hors du catalogue des produits. */
|
|
28
|
-
|
|
36
|
+
const account = product("Account", "Ton compte HGDC : profil, sécurité et organisations, pour tous les produits.", UserCircleIcon, "live");
|
|
37
|
+
export const HGDC_ACCOUNT = { ...account, entryHref: account.href };
|
|
29
38
|
/** Les produits de la famille, dans leur ordre d'affichage. Account n'en fait pas partie (`HGDC_ACCOUNT`). */
|
|
30
39
|
export const HGDC_PRODUCTS = [
|
|
31
40
|
product("Host", "Ton site en ligne, déployé à chaque modification.", Rocket01Icon, "preview"),
|
|
@@ -42,14 +51,16 @@ export function isProductOpen(item) {
|
|
|
42
51
|
/**
|
|
43
52
|
* Les entrées du menu du compte : Account d'abord, puis les produits ouverts. `current` est le
|
|
44
53
|
* mot du produit affiché (« Mail ») : il est coché. `accountHref` remplace l'adresse d'Account
|
|
45
|
-
* (un Account local en développement).
|
|
54
|
+
* (un Account local en développement). Chaque produit pointe vers son entrée (`entryHref`) :
|
|
55
|
+
* un clic ouvre l'app avec la session HGDC, pas la page d'accueil publique.
|
|
46
56
|
*/
|
|
47
57
|
export function productMenuEntries(options = {}) {
|
|
48
58
|
const current = options.current?.toLowerCase();
|
|
49
|
-
const
|
|
59
|
+
const accountHref = options.accountHref ?? HGDC_ACCOUNT.entryHref;
|
|
60
|
+
const account = { ...HGDC_ACCOUNT, href: accountHref, entryHref: accountHref };
|
|
50
61
|
return [account, ...(options.catalog ?? HGDC_PRODUCTS).filter(isProductOpen)].map((item) => ({
|
|
51
62
|
name: item.name,
|
|
52
|
-
href: item.
|
|
63
|
+
href: item.entryHref,
|
|
53
64
|
icon: item.icon,
|
|
54
65
|
...(item.word.toLowerCase() === current ? { current: true } : {}),
|
|
55
66
|
...(item.stage === "preview" ? { hint: PRODUCT_STAGE_LABEL.preview } : {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hgdc/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Interface de la H family : jetons de la DA, thèmes, polices et composants.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://github.com/hugogebel-boop/hgdc-kit/tree/main/packages/ui#readme",
|