@nomosui/react 0.5.2 → 0.6.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/index.js CHANGED
@@ -37,9 +37,11 @@ var cn = (...inputs) => twMerge(clsx(inputs));
37
37
  * statut choisit l'intention (« danger », « succès »), et c'est le cœur qui sait la
38
38
  * rendre — l'app ne manipule plus un nom de couleur.
39
39
  *
40
- * Chaque ton lit deux emplacements sémantiques (`status-<ton>` pour la surface, lue à
41
- * faible opacité, et `status-<ton>-ink` pour l'encre) : c'est le token qui porte le
42
- * mode, pas la classe, donc le cœur ne connaît jamais le mode (ADR 0004, garde des tokens).
40
+ * Chaque ton lit trois emplacements sémantiques (`status-<ton>` pour l'accent, la
41
+ * bordure ; `status-<ton>-surface` pour le fond, **plein** — une carte qui flotte
42
+ * au-dessus du contenu ne doit pas laisser voir ce qui passe dessous ; et `status-<ton>-ink`
43
+ * pour l'encre) : c'est le token qui porte le mode, pas la classe, donc le cœur ne connaît
44
+ * jamais le mode (ADR 0004, ADR 0027).
43
45
  */
44
46
  var TONES = [
45
47
  "neutral",
@@ -52,12 +54,12 @@ var TONES = [
52
54
  ];
53
55
  var toneClasses = {
54
56
  neutral: "border-transparent bg-muted text-muted-foreground",
55
- info: "border-status-info/30 bg-status-info/15 text-status-info-ink",
56
- progress: "border-status-progress/30 bg-status-progress/15 text-status-progress-ink",
57
- attention: "border-status-attention/30 bg-status-attention/15 text-status-attention-ink",
58
- warning: "border-status-warning/30 bg-status-warning/15 text-status-warning-ink",
59
- danger: "border-status-danger/30 bg-status-danger/15 text-status-danger-ink",
60
- success: "border-status-success/30 bg-status-success/15 text-status-success-ink"
57
+ info: "border-status-info/30 bg-status-info-surface text-status-info-ink",
58
+ progress: "border-status-progress/30 bg-status-progress-surface text-status-progress-ink",
59
+ attention: "border-status-attention/30 bg-status-attention-surface text-status-attention-ink",
60
+ warning: "border-status-warning/30 bg-status-warning-surface text-status-warning-ink",
61
+ danger: "border-status-danger/30 bg-status-danger-surface text-status-danger-ink",
62
+ success: "border-status-success/30 bg-status-success-surface text-status-success-ink"
61
63
  };
62
64
  //#endregion
63
65
  //#region src/components/alert/alert.tsx
@@ -934,6 +936,197 @@ var buttonManifest = {
934
936
  ]
935
937
  };
936
938
  //#endregion
939
+ //#region src/components/heading/heading.tsx
940
+ /**
941
+ * La config des variantes est exportée à côté de `headingVariants` : le catalogue la lit
942
+ * pour vérifier que le manifeste ne dérive pas des props réelles (ADR 0005).
943
+ *
944
+ * `level` porte à la fois la balise (`h1`..`h6`) et la taille sémantique : un seul mot dit
945
+ * la hiérarchie, et la taille suit l'échelle des tokens (ADR 0004). Les valeurs sont des
946
+ * chaînes parce que cva indexe ses variantes par nom.
947
+ */
948
+ var headingVariantsConfig = {
949
+ variants: { level: {
950
+ "1": "text-display font-strong",
951
+ "2": "text-title font-strong",
952
+ "3": "text-lead font-strong",
953
+ "4": "text-body font-strong",
954
+ "5": "text-caption font-strong",
955
+ "6": "text-micro font-strong"
956
+ } },
957
+ defaultVariants: { level: "2" }
958
+ };
959
+ var headingVariants = cva("font-sans text-foreground", headingVariantsConfig);
960
+ /**
961
+ * Le titre : la balise suit le niveau (`h1`..`h6`), la taille suit l'échelle sémantique.
962
+ * Présentation seule — le texte vient de l'appelant.
963
+ */
964
+ var Heading = ({ level = 2, className, ...props }) => {
965
+ const Tag = `h${level}`;
966
+ return /* @__PURE__ */ jsx(Tag, {
967
+ className: cn(headingVariants({ level: String(level) }), className),
968
+ ...props
969
+ });
970
+ };
971
+ //#endregion
972
+ //#region src/components/heading/manifest.ts
973
+ /**
974
+ * Le manifeste du Titre (ADR 0005). `level` est la seule variante : elle choisit à la fois
975
+ * la balise (`h1`..`h6`) et la taille sémantique, pour qu'un seul mot dise la hiérarchie.
976
+ */
977
+ var headingManifest = {
978
+ name: "heading",
979
+ title: "Heading",
980
+ summary: "Un titre de section. Le niveau (`level`) choisit la balise `h1`..`h6` et la taille sémantique ; le texte vient de l'appelant.",
981
+ level: "primitive",
982
+ example: {
983
+ level: 2,
984
+ children: "Titre de section"
985
+ },
986
+ variants: [{
987
+ name: "level",
988
+ values: [
989
+ "1",
990
+ "2",
991
+ "3",
992
+ "4",
993
+ "5",
994
+ "6"
995
+ ],
996
+ default: "2",
997
+ description: "Le niveau hiérarchique : il rend la balise `h1`..`h6` correspondante et lit la taille sémantique (display, title, lead, body, caption, micro)."
998
+ }],
999
+ props: [{
1000
+ name: "className",
1001
+ type: "string",
1002
+ required: false,
1003
+ check: "class",
1004
+ description: "Les classes de l'appelant, fusionnées après celles de la variante."
1005
+ }, {
1006
+ name: "children",
1007
+ type: "ReactNode",
1008
+ required: true,
1009
+ check: "content",
1010
+ description: "Le texte du titre : court, il nomme la section."
1011
+ }],
1012
+ usages: [
1013
+ {
1014
+ when: "le titre principal d'une vue",
1015
+ use: "level={1}",
1016
+ avoid: "plusieurs `level={1}` dans une même vue : un seul titre de premier niveau"
1017
+ },
1018
+ {
1019
+ when: "un titre de section sous le titre principal",
1020
+ use: "level={2}",
1021
+ avoid: "sauter un niveau pour grossir un titre : la hiérarchie doit rester continue"
1022
+ },
1023
+ {
1024
+ when: "un sous-titre de bloc ou de carte",
1025
+ use: "level={3}",
1026
+ avoid: "un `level` choisi pour sa taille plutôt que pour la structure du document"
1027
+ }
1028
+ ]
1029
+ };
1030
+ //#endregion
1031
+ //#region src/components/text/text.tsx
1032
+ /**
1033
+ * La config des variantes est exportée à côté de `textVariants` : le catalogue la lit pour
1034
+ * vérifier que le manifeste ne dérive pas des props réelles (ADR 0005).
1035
+ *
1036
+ * `size` lit l'échelle typographique sémantique (ADR 0004) : `text-body`, `text-lead`…
1037
+ * portent la taille **et** l'interligne des tokens.
1038
+ */
1039
+ var textVariantsConfig = {
1040
+ variants: { size: {
1041
+ lead: "text-lead",
1042
+ body: "text-body",
1043
+ caption: "text-caption",
1044
+ micro: "text-micro"
1045
+ } },
1046
+ defaultVariants: { size: "body" }
1047
+ };
1048
+ var textVariants = cva("font-sans text-foreground", textVariantsConfig);
1049
+ /**
1050
+ * Le texte courant : un paragraphe ou un `span`, à la taille sémantique choisie.
1051
+ * Présentation seule — le contenu vient de l'appelant.
1052
+ */
1053
+ var Text = ({ size, as: Tag = "p", className, ...props }) => /* @__PURE__ */ jsx(Tag, {
1054
+ className: cn(textVariants({ size }), className),
1055
+ ...props
1056
+ });
1057
+ //#endregion
1058
+ //#region src/components/text/manifest.ts
1059
+ /**
1060
+ * Le manifeste du Texte (ADR 0005). `size` lit l'échelle typographique sémantique ; `as`
1061
+ * choisit l'élément rendu (paragraphe ou `span` inline).
1062
+ */
1063
+ var textManifest = {
1064
+ name: "text",
1065
+ title: "Text",
1066
+ summary: "Le texte courant. La taille (`size`) vient de l'échelle sémantique ; `as` choisit l'élément rendu, un paragraphe ou un `span` inline.",
1067
+ level: "primitive",
1068
+ example: {
1069
+ size: "body",
1070
+ children: "Un paragraphe de texte courant."
1071
+ },
1072
+ variants: [{
1073
+ name: "size",
1074
+ values: [
1075
+ "lead",
1076
+ "body",
1077
+ "caption",
1078
+ "micro"
1079
+ ],
1080
+ default: "body",
1081
+ description: "La taille sémantique : `lead` pour une accroche, `body` pour le texte courant, `caption` et `micro` pour les mentions secondaires."
1082
+ }],
1083
+ props: [
1084
+ {
1085
+ name: "as",
1086
+ type: "'p' | 'span'",
1087
+ required: false,
1088
+ check: "rendered",
1089
+ description: "L'élément rendu : un paragraphe par défaut, un `span` pour un texte inline."
1090
+ },
1091
+ {
1092
+ name: "className",
1093
+ type: "string",
1094
+ required: false,
1095
+ check: "class",
1096
+ description: "Les classes de l'appelant, fusionnées après celles de la variante."
1097
+ },
1098
+ {
1099
+ name: "children",
1100
+ type: "ReactNode",
1101
+ required: true,
1102
+ check: "content",
1103
+ description: "Le contenu textuel, fourni par l’app."
1104
+ }
1105
+ ],
1106
+ usages: [
1107
+ {
1108
+ when: "un paragraphe de texte courant",
1109
+ use: "size=\"body\"",
1110
+ avoid: "un `size` plus grand pour « faire ressortir » : la hiérarchie passe par `Heading`"
1111
+ },
1112
+ {
1113
+ when: "une accroche ou un chapeau au-dessus du corps",
1114
+ use: "size=\"lead\"",
1115
+ avoid: "un `lead` pour tout le corps : il perd son rôle d’accroche"
1116
+ },
1117
+ {
1118
+ when: "une mention secondaire (légende, aide, horodatage)",
1119
+ use: "size=\"caption\"",
1120
+ avoid: "un `caption` pour du contenu essentiel : il est fait pour être discret"
1121
+ },
1122
+ {
1123
+ when: "un texte inline dans une phrase",
1124
+ use: "as=\"span\"",
1125
+ avoid: "un `span` pour un paragraphe entier : le navigateur perd la structure"
1126
+ }
1127
+ ]
1128
+ };
1129
+ //#endregion
937
1130
  //#region src/components/card/card.tsx
938
1131
  /**
939
1132
  * La carte : une surface qui regroupe un contenu apparenté — un en-tête (titre +
@@ -1536,6 +1729,360 @@ var chipManifest = {
1536
1729
  avoid: "un `Chip` pour un statut de production : un `Badge` dit l’état sans inviter au clic"
1537
1730
  }]
1538
1731
  };
1732
+ /**
1733
+ * La config des variantes est exportée à côté de `kickerVariants` : le catalogue la lit
1734
+ * pour vérifier que le manifeste ne dérive pas des props réelles (ADR 0005). Le ton pose
1735
+ * la couleur du point dans une variable, que le point lit — le libellé reste discret.
1736
+ */
1737
+ var kickerVariantsConfig = {
1738
+ variants: { tone: {
1739
+ neutral: "[--kicker-dot:var(--color-muted-foreground)]",
1740
+ info: "[--kicker-dot:var(--color-status-info)]",
1741
+ progress: "[--kicker-dot:var(--color-status-progress)]",
1742
+ attention: "[--kicker-dot:var(--color-status-attention)]",
1743
+ warning: "[--kicker-dot:var(--color-status-warning)]",
1744
+ danger: "[--kicker-dot:var(--color-status-danger)]",
1745
+ success: "[--kicker-dot:var(--color-status-success)]"
1746
+ } },
1747
+ defaultVariants: { tone: "neutral" }
1748
+ };
1749
+ var kickerVariants = cva("inline-flex items-center gap-1.5 font-mono text-xs uppercase tracking-wider text-muted-foreground", kickerVariantsConfig);
1750
+ /**
1751
+ * Le kicker : une étiquette d'accroche, répétée au-dessus d'un titre. Présentation seule —
1752
+ * le texte est injecté par l'appelant (le cœur n'a pas d'i18n), le ton est une intention.
1753
+ */
1754
+ function Kicker({ tone, dot = false, children, className }) {
1755
+ return /* @__PURE__ */ jsxs("span", {
1756
+ className: cn(kickerVariants({ tone }), className),
1757
+ children: [dot ? /* @__PURE__ */ jsx("span", {
1758
+ "aria-hidden": true,
1759
+ className: "size-1.5 shrink-0 rounded-full bg-[var(--kicker-dot)]"
1760
+ }) : null, children]
1761
+ });
1762
+ }
1763
+ //#endregion
1764
+ //#region src/components/kicker/manifest.ts
1765
+ /** Le manifeste du kicker (ADR 0005). Le ton réutilise le vocabulaire du cœur. */
1766
+ var kickerManifest = {
1767
+ name: "kicker",
1768
+ title: "Kicker",
1769
+ summary: "Une étiquette d'accroche, répétée au-dessus d'un titre : un point de ton optionnel et un libellé court en majuscules. Le texte est injecté par l’appelant.",
1770
+ level: "primitive",
1771
+ example: {
1772
+ tone: "neutral",
1773
+ dot: true,
1774
+ children: "section"
1775
+ },
1776
+ variants: [{
1777
+ name: "tone",
1778
+ values: [...TONES],
1779
+ default: "neutral",
1780
+ description: "L'intention du point — ce que l'appelant choisit selon l'usage."
1781
+ }],
1782
+ props: [
1783
+ {
1784
+ name: "children",
1785
+ type: "ReactNode",
1786
+ required: true,
1787
+ check: "content",
1788
+ description: "Le libellé d'accroche : court, jamais une phrase."
1789
+ },
1790
+ {
1791
+ name: "dot",
1792
+ type: "boolean",
1793
+ required: false,
1794
+ check: "rendered",
1795
+ description: "Affiche un point de ton devant le libellé."
1796
+ },
1797
+ {
1798
+ name: "className",
1799
+ type: "string",
1800
+ required: false,
1801
+ check: "class",
1802
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
1803
+ }
1804
+ ],
1805
+ usages: [{
1806
+ when: "coiffer un titre d’une accroche courte",
1807
+ use: "<Kicker dot>section</Kicker>",
1808
+ avoid: "un `Badge` : le kicker situe un titre, il ne qualifie pas un statut"
1809
+ }, {
1810
+ when: "marquer une intention sur l’accroche",
1811
+ use: "<Kicker tone=\"danger\" dot>attention</Kicker>",
1812
+ avoid: "une couleur en dur : le ton est une intention, le token porte la valeur"
1813
+ }]
1814
+ };
1815
+ //#endregion
1816
+ //#region src/components/copy-button/copy-button.tsx
1817
+ /**
1818
+ * La config de variantes du CopyButton : celle du Button, réutilisée telle quelle. Le
1819
+ * catalogue la lit pour vérifier que le manifeste ne dérive pas des props réelles
1820
+ * (ADR 0005).
1821
+ */
1822
+ var copyButtonVariantsConfig = buttonVariantsConfig;
1823
+ /** Le temps pendant lequel le libellé « copié » reste affiché avant de revenir. */
1824
+ var COPIED_MS = 2e3;
1825
+ /**
1826
+ * Le bouton de copie : il écrit `value` dans le presse-papiers et affiche un libellé
1827
+ * transitoire. Copier du texte arbitraire n'est pas un souci d'app (ADR 0002) ; les
1828
+ * libellés et l'icône sont injectés, le cœur n'a pas d'i18n.
1829
+ */
1830
+ function CopyButton({ value, label = "Copy", copiedLabel = "Copied", icon, variant, size, className }) {
1831
+ const [copied, setCopied] = useState(false);
1832
+ useEffect(() => {
1833
+ if (!copied) return;
1834
+ const timer = setTimeout(() => setCopied(false), COPIED_MS);
1835
+ return () => clearTimeout(timer);
1836
+ }, [copied]);
1837
+ return /* @__PURE__ */ jsxs(Button, {
1838
+ type: "button",
1839
+ variant,
1840
+ size,
1841
+ className,
1842
+ onClick: () => {
1843
+ navigator.clipboard.writeText(value).then(() => setCopied(true));
1844
+ },
1845
+ children: [icon ? /* @__PURE__ */ jsx("span", {
1846
+ "aria-hidden": true,
1847
+ children: icon
1848
+ }) : null, copied ? copiedLabel : label]
1849
+ });
1850
+ }
1851
+ //#endregion
1852
+ //#region src/components/copy-button/manifest.ts
1853
+ /**
1854
+ * Le manifeste du CopyButton (ADR 0005). Il reprend les deux groupes de variantes du
1855
+ * Button — `variant` et `size` — que le test de cohérence confronte à la config réelle.
1856
+ */
1857
+ var copyButtonManifest = {
1858
+ name: "copy-button",
1859
+ title: "CopyButton",
1860
+ summary: "Un bouton qui copie un texte dans le presse-papiers et affiche un libellé transitoire. Les libellés et l’icône sont injectés : le cœur n’a pas d’i18n.",
1861
+ level: "primitive",
1862
+ example: { value: "npm install @nomosui/react" },
1863
+ variants: [{
1864
+ name: "variant",
1865
+ values: [
1866
+ "default",
1867
+ "destructive",
1868
+ "outline",
1869
+ "secondary",
1870
+ "ghost",
1871
+ "link"
1872
+ ],
1873
+ default: "default",
1874
+ description: "Le ton de l'action, repris du Button."
1875
+ }, {
1876
+ name: "size",
1877
+ values: [
1878
+ "default",
1879
+ "sm",
1880
+ "lg",
1881
+ "icon"
1882
+ ],
1883
+ default: "default",
1884
+ description: "La taille du contrôle, reprise du Button."
1885
+ }],
1886
+ props: [
1887
+ {
1888
+ name: "value",
1889
+ type: "string",
1890
+ required: true,
1891
+ check: "accepted",
1892
+ description: "Le texte à copier dans le presse-papiers."
1893
+ },
1894
+ {
1895
+ name: "label",
1896
+ type: "string",
1897
+ required: false,
1898
+ default: "Copy",
1899
+ check: "accepted",
1900
+ description: "Le libellé au repos, injecté par l’app."
1901
+ },
1902
+ {
1903
+ name: "copiedLabel",
1904
+ type: "string",
1905
+ required: false,
1906
+ default: "Copied",
1907
+ check: "accepted",
1908
+ description: "Le libellé transitoire affiché après la copie."
1909
+ },
1910
+ {
1911
+ name: "icon",
1912
+ type: "ReactNode",
1913
+ required: false,
1914
+ check: "accepted",
1915
+ description: "Une icône fournie par l’appelant ; le cœur n’expose pas d’icônes."
1916
+ },
1917
+ {
1918
+ name: "className",
1919
+ type: "string",
1920
+ required: false,
1921
+ check: "class",
1922
+ description: "Les classes de l'appelant, fusionnées après celles de la variante."
1923
+ }
1924
+ ],
1925
+ usages: [
1926
+ {
1927
+ when: "offrir de copier une valeur courte (un identifiant, une commande)",
1928
+ use: "value + label",
1929
+ avoid: "un libellé produit en dur : l’app injecte le texte traduit"
1930
+ },
1931
+ {
1932
+ when: "signaler la copie sans changer de vue",
1933
+ use: "copiedLabel",
1934
+ avoid: "un toast en plus : le libellé transitoire suffit"
1935
+ },
1936
+ {
1937
+ when: "poser une icône à côté du libellé",
1938
+ use: "icon",
1939
+ avoid: "une icône seule sans `aria-label` : le bouton devient muet"
1940
+ }
1941
+ ]
1942
+ };
1943
+ //#endregion
1944
+ //#region src/components/code/code.tsx
1945
+ function Code({ className, ...props }) {
1946
+ return /* @__PURE__ */ jsx("code", {
1947
+ className: cn("rounded border bg-muted px-1.5 py-0.5 font-mono text-[0.85em] text-foreground", className),
1948
+ ...props
1949
+ });
1950
+ }
1951
+ //#endregion
1952
+ //#region src/components/code/manifest.ts
1953
+ /**
1954
+ * Le manifeste du Code inline (ADR 0005). Il est écrit à la main : le type se génère,
1955
+ * l'usage s'écrit. Le test de cohérence du catalogue le confronte aux props réelles.
1956
+ */
1957
+ var codeManifest = {
1958
+ name: "code",
1959
+ title: "Code",
1960
+ summary: "Un extrait de code inline : une surface monospace discrète, posée dans une phrase. Le fond inset, la bordure et le rayon viennent des tokens ; la coloration syntaxique reste à l'app.",
1961
+ level: "primitive",
1962
+ example: { children: "npm install @nomosui/react" },
1963
+ variants: [],
1964
+ props: [{
1965
+ name: "children",
1966
+ type: "ReactNode",
1967
+ required: true,
1968
+ check: "content",
1969
+ description: "Le texte de l'extrait, injecté par l'appelant."
1970
+ }, {
1971
+ name: "className",
1972
+ type: "string",
1973
+ required: false,
1974
+ check: "class",
1975
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
1976
+ }],
1977
+ usages: [{
1978
+ when: "citer un identifiant, une commande ou un nom de fichier dans une phrase",
1979
+ use: "Code",
1980
+ avoid: "un `CodeBlock` pour un mot : le bloc casse la ligne de texte"
1981
+ }, {
1982
+ when: "poser sa propre coloration syntaxique",
1983
+ use: "children avec des nœuds colorés",
1984
+ avoid: "attendre la coloration du cœur : elle est hors périmètre"
1985
+ }]
1986
+ };
1987
+ //#endregion
1988
+ //#region src/components/code-block/code-block.tsx
1989
+ function CodeBlock({ code, children, copyLabel, copiedLabel, showCopy = true, className }) {
1990
+ const copyValue = code ?? (typeof children === "string" ? children : "");
1991
+ return /* @__PURE__ */ jsxs("div", {
1992
+ className: cn("relative rounded-md border bg-muted", className),
1993
+ children: [showCopy ? /* @__PURE__ */ jsx("div", {
1994
+ className: "absolute right-2 top-2",
1995
+ children: /* @__PURE__ */ jsx(CopyButton, {
1996
+ value: copyValue,
1997
+ label: copyLabel,
1998
+ copiedLabel,
1999
+ size: "sm"
2000
+ })
2001
+ }) : null, /* @__PURE__ */ jsx("pre", {
2002
+ className: "overflow-x-auto p-4 font-mono text-sm",
2003
+ children: /* @__PURE__ */ jsx("code", { children: children ?? code })
2004
+ })]
2005
+ });
2006
+ }
2007
+ //#endregion
2008
+ //#region src/components/code-block/manifest.ts
2009
+ /**
2010
+ * Le manifeste du CodeBlock (ADR 0005). Il est écrit à la main : le type se génère,
2011
+ * l'usage s'écrit. Le test de cohérence du catalogue le confronte aux props réelles.
2012
+ */
2013
+ var codeBlockManifest = {
2014
+ name: "code-block",
2015
+ title: "CodeBlock",
2016
+ summary: "Un bloc de code monospace scrollable, avec un bouton de copie. `code` est le texte brut copié, `children` le rendu (l’app peut y poser sa coloration) ; les libellés sont injectés, le cœur n'a pas d'i18n.",
2017
+ level: "primitive",
2018
+ example: {
2019
+ code: "npm install @nomosui/react",
2020
+ showCopy: true
2021
+ },
2022
+ variants: [],
2023
+ props: [
2024
+ {
2025
+ name: "code",
2026
+ type: "string",
2027
+ required: false,
2028
+ check: "accepted",
2029
+ description: "Le texte brut à copier, et le contenu affiché si `children` est absent."
2030
+ },
2031
+ {
2032
+ name: "children",
2033
+ type: "ReactNode",
2034
+ required: false,
2035
+ check: "content",
2036
+ description: "Le contenu affiché ; permet à l’app de poser sa propre coloration."
2037
+ },
2038
+ {
2039
+ name: "copyLabel",
2040
+ type: "string",
2041
+ required: false,
2042
+ check: "accepted",
2043
+ description: "Le libellé du bouton de copie, injecté par l’app."
2044
+ },
2045
+ {
2046
+ name: "copiedLabel",
2047
+ type: "string",
2048
+ required: false,
2049
+ check: "accepted",
2050
+ description: "Le libellé transitoire affiché après la copie."
2051
+ },
2052
+ {
2053
+ name: "showCopy",
2054
+ type: "boolean",
2055
+ required: false,
2056
+ default: "true",
2057
+ check: "rendered",
2058
+ description: "Affiche le bouton de copie."
2059
+ },
2060
+ {
2061
+ name: "className",
2062
+ type: "string",
2063
+ required: false,
2064
+ check: "class",
2065
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
2066
+ }
2067
+ ],
2068
+ usages: [
2069
+ {
2070
+ when: "montrer un extrait de code de plusieurs lignes",
2071
+ use: "CodeBlock avec `code`",
2072
+ avoid: "un `Code` inline : le bloc est fait pour un extrait, pas un mot"
2073
+ },
2074
+ {
2075
+ when: "offrir de copier l’extrait",
2076
+ use: "showCopy (défaut) + copyLabel/copiedLabel injectés",
2077
+ avoid: "un libellé produit en dur : l’app injecte le texte traduit"
2078
+ },
2079
+ {
2080
+ when: "colorer la syntaxe",
2081
+ use: "children avec des nœuds colorés, `code` restant le texte copié",
2082
+ avoid: "attendre la coloration du cœur : elle est hors périmètre"
2083
+ }
2084
+ ]
2085
+ };
1539
2086
  //#endregion
1540
2087
  //#region src/components/freshness/freshness.tsx
1541
2088
  function Freshness({ label, title, stale = false, className, ...props }) {
@@ -1990,6 +2537,224 @@ var labelManifest = {
1990
2537
  }]
1991
2538
  };
1992
2539
  //#endregion
2540
+ //#region src/components/link/link.tsx
2541
+ function Link({ className, asChild = false, ...props }) {
2542
+ return /* @__PURE__ */ jsx(asChild ? Slot : "a", {
2543
+ className: cn("text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className),
2544
+ ...props
2545
+ });
2546
+ }
2547
+ //#endregion
2548
+ //#region src/components/link/manifest.ts
2549
+ /**
2550
+ * Le manifeste du Lien (ADR 0005). Il est écrit à la main : le type se génère,
2551
+ * l'usage s'écrit. Le test de cohérence du catalogue le confronte aux props réelles.
2552
+ */
2553
+ var linkManifest = {
2554
+ name: "link",
2555
+ title: "Link",
2556
+ summary: "Un lien texte qui rend un `<a>`. `href` et le libellé sont injectés : le cœur ne porte aucun routing. Tout attribut HTML d’ancre est transmis tel quel.",
2557
+ level: "primitive",
2558
+ example: {
2559
+ children: "Documentation",
2560
+ href: "#"
2561
+ },
2562
+ variants: [],
2563
+ props: [
2564
+ {
2565
+ name: "className",
2566
+ type: "string",
2567
+ required: false,
2568
+ check: "class",
2569
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
2570
+ },
2571
+ {
2572
+ name: "children",
2573
+ type: "ReactNode",
2574
+ required: true,
2575
+ check: "content",
2576
+ description: "Le libellé du lien, injecté par l’appelant."
2577
+ },
2578
+ {
2579
+ name: "href",
2580
+ type: "string",
2581
+ required: false,
2582
+ check: "attribute",
2583
+ description: "La destination, transmise telle quelle à l'ancre ; le cœur ne la connaît pas."
2584
+ }
2585
+ ],
2586
+ usages: [{
2587
+ when: "naviguer vers une URL",
2588
+ use: "Link avec `href`",
2589
+ avoid: "un `Button` pour une navigation : le lien doit rester un `<a>`"
2590
+ }, {
2591
+ when: "poser le style du lien sur un composant de routing de l’app",
2592
+ use: "asChild avec un seul enfant",
2593
+ avoid: "asChild avec plusieurs enfants : Radix Slot n’en accepte qu’un"
2594
+ }]
2595
+ };
2596
+ //#endregion
2597
+ //#region src/components/navbar/navbar.tsx
2598
+ function Navbar({ brand, nav, actions, className }) {
2599
+ return /* @__PURE__ */ jsxs("header", {
2600
+ className: cn("sticky top-0 flex h-14 items-center gap-4 border-b border-border bg-background px-4 text-foreground", className),
2601
+ children: [
2602
+ brand ? /* @__PURE__ */ jsx("div", {
2603
+ className: "flex items-center gap-2 font-semibold",
2604
+ children: brand
2605
+ }) : null,
2606
+ nav ? /* @__PURE__ */ jsx("nav", {
2607
+ className: "flex flex-1 items-center gap-4",
2608
+ children: nav
2609
+ }) : null,
2610
+ actions ? /* @__PURE__ */ jsx("div", {
2611
+ className: "ml-auto flex items-center gap-2",
2612
+ children: actions
2613
+ }) : null
2614
+ ]
2615
+ });
2616
+ }
2617
+ //#endregion
2618
+ //#region src/components/navbar/manifest.ts
2619
+ /** Le manifeste de la barre supérieure (ADR 0005, 0030). Slots injectés, aucun routing. */
2620
+ var navbarManifest = {
2621
+ name: "navbar",
2622
+ title: "Navbar",
2623
+ summary: "La barre supérieure d'un site : une marque, des emplacements de navigation et un groupe d'actions en fin. Sticky en haut, bordure basse, fond du cœur. Les slots sont injectés — le cœur ne porte ni routing ni mot produit (ADR 0002, 0030).",
2624
+ level: "bloc",
2625
+ example: {
2626
+ brand: "Nomos",
2627
+ nav: createElement("a", {
2628
+ href: "#",
2629
+ key: "docs"
2630
+ }, "Docs"),
2631
+ actions: createElement("button", {
2632
+ type: "button",
2633
+ key: "action"
2634
+ }, "Action")
2635
+ },
2636
+ variants: [],
2637
+ props: [
2638
+ {
2639
+ name: "brand",
2640
+ type: "ReactNode",
2641
+ required: false,
2642
+ check: "accepted",
2643
+ description: "La marque : un wordmark, un logo, un badge de version."
2644
+ },
2645
+ {
2646
+ name: "nav",
2647
+ type: "ReactNode",
2648
+ required: false,
2649
+ check: "accepted",
2650
+ description: "Les emplacements de navigation, fournis par l’appelant."
2651
+ },
2652
+ {
2653
+ name: "actions",
2654
+ type: "ReactNode",
2655
+ required: false,
2656
+ check: "accepted",
2657
+ description: "Le groupe d’actions de fin : boutons, menu, avatar."
2658
+ },
2659
+ {
2660
+ name: "className",
2661
+ type: "string",
2662
+ required: false,
2663
+ check: "class",
2664
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
2665
+ }
2666
+ ],
2667
+ usages: [{
2668
+ when: "poser l’en-tête d’un site : marque, navigation, actions",
2669
+ use: "<Navbar brand={<Wordmark/>} nav={<AppNav/>} actions={<Button…/>} />",
2670
+ avoid: "un `<header>` stylé au coup par coup : on perd les tokens de bordure et de fond"
2671
+ }, {
2672
+ when: "les liens et les libellés de navigation",
2673
+ use: "des slots injectés par l’app (ADR 0015)",
2674
+ avoid: "un `href` ou un mot produit en dur dans le cœur : le routing appartient à l’app"
2675
+ }]
2676
+ };
2677
+ //#endregion
2678
+ //#region src/components/footer/footer.tsx
2679
+ function Footer({ brand, links, legal, className }) {
2680
+ return /* @__PURE__ */ jsxs("footer", {
2681
+ className: cn("border-t bg-background text-foreground", className),
2682
+ children: [/* @__PURE__ */ jsxs("div", {
2683
+ className: "mx-auto flex max-w-6xl flex-col gap-4 px-6 py-8 sm:flex-row sm:items-center sm:justify-between",
2684
+ children: [brand ? /* @__PURE__ */ jsx("div", {
2685
+ className: "font-semibold",
2686
+ children: brand
2687
+ }) : null, links ? /* @__PURE__ */ jsx("nav", {
2688
+ className: "flex flex-wrap items-center gap-x-6 gap-y-2 text-sm",
2689
+ children: links
2690
+ }) : null]
2691
+ }), legal ? /* @__PURE__ */ jsx("div", {
2692
+ className: "border-t",
2693
+ children: /* @__PURE__ */ jsx("div", {
2694
+ className: "mx-auto max-w-6xl px-6 py-4 text-sm text-muted-foreground",
2695
+ children: legal
2696
+ })
2697
+ }) : null]
2698
+ });
2699
+ }
2700
+ //#endregion
2701
+ //#region src/components/footer/manifest.ts
2702
+ /**
2703
+ * Le manifeste du pied de page (ADR 0005, ADR 0015). Un bloc du cœur : la mise en page
2704
+ * est au cœur, les emplacements (marque, liens, ligne légale) sont injectés par l'app.
2705
+ */
2706
+ var footerManifest = {
2707
+ name: "footer",
2708
+ title: "Footer",
2709
+ summary: "Le pied de page : une marque, une rangée de liens et une ligne légale. Des emplacements injectés, sans routing ni libellé propre au cœur (ADR 0002).",
2710
+ level: "bloc",
2711
+ example: {
2712
+ brand: "Nomos",
2713
+ links: "Documentation · GitHub",
2714
+ legal: "© 2026 Nomos"
2715
+ },
2716
+ variants: [],
2717
+ props: [
2718
+ {
2719
+ name: "brand",
2720
+ type: "ReactNode",
2721
+ required: false,
2722
+ check: "accepted",
2723
+ description: "Le wordmark ou le logo, fourni par l’appelant."
2724
+ },
2725
+ {
2726
+ name: "links",
2727
+ type: "ReactNode",
2728
+ required: false,
2729
+ check: "accepted",
2730
+ description: "La rangée de liens, fournie par l’appelant (des `Link`, par exemple)."
2731
+ },
2732
+ {
2733
+ name: "legal",
2734
+ type: "ReactNode",
2735
+ required: false,
2736
+ check: "accepted",
2737
+ description: "La ligne légale (copyright, mentions), fournie par l’appelant."
2738
+ },
2739
+ {
2740
+ name: "className",
2741
+ type: "string",
2742
+ required: false,
2743
+ check: "class",
2744
+ description: "Les classes de l'appelant, fusionnées après celles du cœur."
2745
+ }
2746
+ ],
2747
+ usages: [{
2748
+ when: "poser un pied de page sous le contenu d’une vue",
2749
+ use: "<Footer brand={<Wordmark/>} links={<><Link…/><Link…/></>} legal={t('legal')} />",
2750
+ avoid: "un `<footer>` stylé au coup par coup : on perd les tokens de bordure et de fond"
2751
+ }, {
2752
+ when: "un pied minimal, sans ligne légale",
2753
+ use: "omettre `legal` : le bloc se réduit à la marque et aux liens",
2754
+ avoid: "un emplacement vide rendu pour rien — un slot absent ne rend rien"
2755
+ }]
2756
+ };
2757
+ //#endregion
1993
2758
  //#region src/components/fieldset/fieldset.tsx
1994
2759
  /** Un regroupement de champs apparentés ; l'app fournit le titre (`legend`). */
1995
2760
  function Fieldset({ className, ...props }) {
@@ -5264,6 +6029,29 @@ var catalogueEntries = [
5264
6029
  }
5265
6030
  }
5266
6031
  },
6032
+ {
6033
+ manifest: kickerManifest,
6034
+ component: Kicker,
6035
+ variantsConfig: { tone: kickerVariantsConfig }
6036
+ },
6037
+ {
6038
+ manifest: copyButtonManifest,
6039
+ component: CopyButton,
6040
+ variantsConfig: {
6041
+ variant: copyButtonVariantsConfig,
6042
+ size: copyButtonVariantsConfig
6043
+ }
6044
+ },
6045
+ {
6046
+ manifest: codeManifest,
6047
+ component: Code,
6048
+ variantsConfig: {}
6049
+ },
6050
+ {
6051
+ manifest: codeBlockManifest,
6052
+ component: CodeBlock,
6053
+ variantsConfig: {}
6054
+ },
5267
6055
  {
5268
6056
  manifest: freshnessManifest,
5269
6057
  component: Freshness,
@@ -5299,6 +6087,21 @@ var catalogueEntries = [
5299
6087
  component: Label,
5300
6088
  variantsConfig: {}
5301
6089
  },
6090
+ {
6091
+ manifest: linkManifest,
6092
+ component: Link,
6093
+ variantsConfig: {}
6094
+ },
6095
+ {
6096
+ manifest: navbarManifest,
6097
+ component: Navbar,
6098
+ variantsConfig: {}
6099
+ },
6100
+ {
6101
+ manifest: footerManifest,
6102
+ component: Footer,
6103
+ variantsConfig: {}
6104
+ },
5302
6105
  {
5303
6106
  manifest: fieldsetManifest,
5304
6107
  component: Fieldset,
@@ -5427,6 +6230,16 @@ var catalogueEntries = [
5427
6230
  manifest: timelineManifest,
5428
6231
  component: Timeline,
5429
6232
  variantsConfig: {}
6233
+ },
6234
+ {
6235
+ manifest: headingManifest,
6236
+ component: Heading,
6237
+ variantsConfig: { level: headingVariantsConfig }
6238
+ },
6239
+ {
6240
+ manifest: textManifest,
6241
+ component: Text,
6242
+ variantsConfig: { size: textVariantsConfig }
5430
6243
  }
5431
6244
  ];
5432
6245
  /**
@@ -5683,16 +6496,22 @@ var tokensResource = {
5683
6496
  "--nomos-color-brand": "#00c9b1",
5684
6497
  "--nomos-color-scrim": "0 0% 0% / 0.8",
5685
6498
  "--nomos-color-status-info": "199 89% 48%",
6499
+ "--nomos-color-status-info-surface": "202 49% 14%",
5686
6500
  "--nomos-color-status-info-ink": "198 93% 74%",
5687
6501
  "--nomos-color-status-progress": "258 90% 66%",
6502
+ "--nomos-color-status-progress-surface": "256 30% 17%",
5688
6503
  "--nomos-color-status-progress-ink": "255 92% 85%",
5689
6504
  "--nomos-color-status-attention": "38 92% 50%",
6505
+ "--nomos-color-status-attention-surface": "36 45% 14%",
5690
6506
  "--nomos-color-status-attention-ink": "46 97% 65%",
5691
6507
  "--nomos-color-status-warning": "25 95% 53%",
6508
+ "--nomos-color-status-warning-surface": "22 42% 15%",
5692
6509
  "--nomos-color-status-warning-ink": "31 97% 72%",
5693
6510
  "--nomos-color-status-danger": "0 84% 60%",
6511
+ "--nomos-color-status-danger-surface": "354 33% 15%",
5694
6512
  "--nomos-color-status-danger-ink": "0 94% 82%",
5695
6513
  "--nomos-color-status-success": "160 84% 39%",
6514
+ "--nomos-color-status-success-surface": "166 40% 12%",
5696
6515
  "--nomos-color-status-success-ink": "156 72% 67%",
5697
6516
  "--nomos-radius-pill": "9999px",
5698
6517
  "--nomos-radius-control": "0.625rem",
@@ -5755,16 +6574,22 @@ var tokensResource = {
5755
6574
  "--nomos-color-brand": "#00c9b1",
5756
6575
  "--nomos-color-scrim": "0 0% 0% / 0.8",
5757
6576
  "--nomos-color-status-info": "199 89% 48%",
6577
+ "--nomos-color-status-info-surface": "199 82% 92%",
5758
6578
  "--nomos-color-status-info-ink": "201 96% 32%",
5759
6579
  "--nomos-color-status-progress": "258 90% 66%",
6580
+ "--nomos-color-status-progress-surface": "258 90% 95%",
5760
6581
  "--nomos-color-status-progress-ink": "263 70% 50%",
5761
6582
  "--nomos-color-status-attention": "38 92% 50%",
6583
+ "--nomos-color-status-attention-surface": "38 92% 93%",
5762
6584
  "--nomos-color-status-attention-ink": "26 90% 37%",
5763
6585
  "--nomos-color-status-warning": "25 95% 53%",
6586
+ "--nomos-color-status-warning-surface": "25 95% 93%",
5764
6587
  "--nomos-color-status-warning-ink": "17 88% 40%",
5765
6588
  "--nomos-color-status-danger": "0 84% 60%",
6589
+ "--nomos-color-status-danger-surface": "0 84% 94%",
5766
6590
  "--nomos-color-status-danger-ink": "0 74% 42%",
5767
6591
  "--nomos-color-status-success": "160 84% 39%",
6592
+ "--nomos-color-status-success-surface": "160 54% 91%",
5768
6593
  "--nomos-color-status-success-ink": "161 94% 25%",
5769
6594
  "--nomos-radius-pill": "9999px",
5770
6595
  "--nomos-radius-control": "0.625rem",
@@ -5807,4 +6632,4 @@ var tokensResource = {
5807
6632
  }
5808
6633
  };
5809
6634
  //#endregion
5810
- export { Accordion, AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, Collapsible, CollapsibleContent, CollapsibleTrigger, CompactMeter, Counter, DataTablePagination, DataTableToolbar, Dialog, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FacetFilter, FacetedDataTable, Field, Fieldset, Form, Freshness, Input, Label, Meter, NumberField, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Rating, ScrollArea, ScrollBar, SearchField, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectionTree, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, Switch, TONES, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Timeline, Toast, ToastProvider, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tree, accordionManifest, alertDialogManifest, alertManifest, avatarManifest, badgeManifest, badgeVariants, badgeVariantsConfig, buttonManifest, buttonVariants, buttonVariantsConfig, cardManifest, catalogue, checkboxManifest, chipManifest, cn, collapsibleManifest, componentManifestSchema, componentNames, counterManifest, dataTableFeatures, dataTablePaginationManifest, dataTableToolbarManifest, dialogManifest, dropdownMenuManifest, emptyStateManifest, facetFilterManifest, fieldManifest, fieldsetManifest, findComponent, formManifest, freshnessManifest, inputManifest, labelManifest, meterManifest, numberFieldManifest, popoverManifest, progressBarManifest, radioManifest, ratingManifest, renderCss, resolveSkin, scrollAreaManifest, searchFieldManifest, selectManifest, separatorManifest, sheetManifest, skeletonManifest, switchManifest, tableManifest, tabsManifest, textareaManifest, timelineManifest, toastManifest, toggleGroupManifest, toggleManifest, toggleVariants, toggleVariantsConfig, tokensResource, toneClasses, tooltipManifest, treeManifest, useToast, validateCatalogue };
6635
+ export { Accordion, AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, Code, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CompactMeter, CopyButton, Counter, DataTablePagination, DataTableToolbar, Dialog, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, FacetFilter, FacetedDataTable, Field, Fieldset, Footer, Form, Freshness, Heading, Input, Kicker, Label, Link, Meter, Navbar, NumberField, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressBar, RadioGroup, RadioGroupItem, Rating, ScrollArea, ScrollBar, SearchField, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectionTree, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Skeleton, Switch, TONES, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, Timeline, Toast, ToastProvider, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tree, accordionManifest, alertDialogManifest, alertManifest, avatarManifest, badgeManifest, badgeVariants, badgeVariantsConfig, buttonManifest, buttonVariants, buttonVariantsConfig, cardManifest, catalogue, checkboxManifest, chipManifest, cn, codeBlockManifest, codeManifest, collapsibleManifest, componentManifestSchema, componentNames, copyButtonManifest, copyButtonVariantsConfig, counterManifest, dataTableFeatures, dataTablePaginationManifest, dataTableToolbarManifest, dialogManifest, dropdownMenuManifest, emptyStateManifest, facetFilterManifest, fieldManifest, fieldsetManifest, findComponent, footerManifest, formManifest, freshnessManifest, headingManifest, headingVariants, headingVariantsConfig, inputManifest, kickerManifest, kickerVariantsConfig, labelManifest, linkManifest, meterManifest, navbarManifest, numberFieldManifest, popoverManifest, progressBarManifest, radioManifest, ratingManifest, renderCss, resolveSkin, scrollAreaManifest, searchFieldManifest, selectManifest, separatorManifest, sheetManifest, skeletonManifest, switchManifest, tableManifest, tabsManifest, textManifest, textVariants, textVariantsConfig, textareaManifest, timelineManifest, toastManifest, toggleGroupManifest, toggleManifest, toggleVariants, toggleVariantsConfig, tokensResource, toneClasses, tooltipManifest, treeManifest, useToast, validateCatalogue };