@nomosui/react 0.5.3 → 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
@@ -936,6 +936,197 @@ var buttonManifest = {
936
936
  ]
937
937
  };
938
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
939
1130
  //#region src/components/card/card.tsx
940
1131
  /**
941
1132
  * La carte : une surface qui regroupe un contenu apparenté — un en-tête (titre +
@@ -1538,6 +1729,360 @@ var chipManifest = {
1538
1729
  avoid: "un `Chip` pour un statut de production : un `Badge` dit l’état sans inviter au clic"
1539
1730
  }]
1540
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
+ };
1541
2086
  //#endregion
1542
2087
  //#region src/components/freshness/freshness.tsx
1543
2088
  function Freshness({ label, title, stale = false, className, ...props }) {
@@ -1992,6 +2537,224 @@ var labelManifest = {
1992
2537
  }]
1993
2538
  };
1994
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
1995
2758
  //#region src/components/fieldset/fieldset.tsx
1996
2759
  /** Un regroupement de champs apparentés ; l'app fournit le titre (`legend`). */
1997
2760
  function Fieldset({ className, ...props }) {
@@ -5266,6 +6029,29 @@ var catalogueEntries = [
5266
6029
  }
5267
6030
  }
5268
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
+ },
5269
6055
  {
5270
6056
  manifest: freshnessManifest,
5271
6057
  component: Freshness,
@@ -5301,6 +6087,21 @@ var catalogueEntries = [
5301
6087
  component: Label,
5302
6088
  variantsConfig: {}
5303
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
+ },
5304
6105
  {
5305
6106
  manifest: fieldsetManifest,
5306
6107
  component: Fieldset,
@@ -5429,6 +6230,16 @@ var catalogueEntries = [
5429
6230
  manifest: timelineManifest,
5430
6231
  component: Timeline,
5431
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 }
5432
6243
  }
5433
6244
  ];
5434
6245
  /**
@@ -5821,4 +6632,4 @@ var tokensResource = {
5821
6632
  }
5822
6633
  };
5823
6634
  //#endregion
5824
- 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 };