@situaction/traquiste-docs-kit 0.0.0-stage → 1.1.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +356 -2
  3. package/client.d.ts +7 -0
  4. package/dist/app/ColorModeContext.d.ts +15 -0
  5. package/dist/app/ColorModeContext.d.ts.map +1 -0
  6. package/dist/app/ColorModeContext.js +58 -0
  7. package/dist/app/config.d.ts +69 -0
  8. package/dist/app/config.d.ts.map +1 -0
  9. package/dist/app/config.js +35 -0
  10. package/dist/app/createDocsApp.d.ts +9 -0
  11. package/dist/app/createDocsApp.d.ts.map +1 -0
  12. package/dist/app/createDocsApp.js +53 -0
  13. package/dist/components/Callout.d.ts +11 -0
  14. package/dist/components/Callout.d.ts.map +1 -0
  15. package/dist/components/Callout.js +28 -0
  16. package/dist/components/CodeBlock.d.ts +12 -0
  17. package/dist/components/CodeBlock.d.ts.map +1 -0
  18. package/dist/components/CodeBlock.js +60 -0
  19. package/dist/components/DeviceFrame.d.ts +17 -0
  20. package/dist/components/DeviceFrame.d.ts.map +1 -0
  21. package/dist/components/DeviceFrame.js +74 -0
  22. package/dist/components/LiveEditor.d.ts +10 -0
  23. package/dist/components/LiveEditor.d.ts.map +1 -0
  24. package/dist/components/LiveEditor.js +231 -0
  25. package/dist/components/PropsTable.d.ts +16 -0
  26. package/dist/components/PropsTable.d.ts.map +1 -0
  27. package/dist/components/PropsTable.js +60 -0
  28. package/dist/components/layout/ComponentSearch.d.ts +2 -0
  29. package/dist/components/layout/ComponentSearch.d.ts.map +1 -0
  30. package/dist/components/layout/ComponentSearch.js +156 -0
  31. package/dist/components/layout/Layout.d.ts +8 -0
  32. package/dist/components/layout/Layout.d.ts.map +1 -0
  33. package/dist/components/layout/Layout.js +109 -0
  34. package/dist/components/layout/NotFound.d.ts +2 -0
  35. package/dist/components/layout/NotFound.d.ts.map +1 -0
  36. package/dist/components/layout/NotFound.js +36 -0
  37. package/dist/components/layout/Sidebar.d.ts +2 -0
  38. package/dist/components/layout/Sidebar.d.ts.map +1 -0
  39. package/dist/components/layout/Sidebar.js +88 -0
  40. package/dist/components/layout/TableOfContents.d.ts +10 -0
  41. package/dist/components/layout/TableOfContents.d.ts.map +1 -0
  42. package/dist/components/layout/TableOfContents.js +48 -0
  43. package/dist/hooks/useCopy.d.ts +5 -0
  44. package/dist/hooks/useCopy.d.ts.map +1 -0
  45. package/dist/hooks/useCopy.js +19 -0
  46. package/dist/index.d.ts +21 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +13 -0
  49. package/dist/pages/DocPage.d.ts +26 -0
  50. package/dist/pages/DocPage.d.ts.map +1 -0
  51. package/dist/pages/DocPage.js +23 -0
  52. package/dist/pages/createComponentPage.d.ts +33 -0
  53. package/dist/pages/createComponentPage.d.ts.map +1 -0
  54. package/dist/pages/createComponentPage.js +150 -0
  55. package/dist/pages/createScreenPage.d.ts +33 -0
  56. package/dist/pages/createScreenPage.d.ts.map +1 -0
  57. package/dist/pages/createScreenPage.js +124 -0
  58. package/dist/styles/docs.css +177 -0
  59. package/dist/styles/pageStyles.d.ts +45 -0
  60. package/dist/styles/pageStyles.d.ts.map +1 -0
  61. package/dist/styles/pageStyles.js +46 -0
  62. package/dist/vite/extractProps.d.ts +8 -0
  63. package/dist/vite/extractProps.d.ts.map +1 -0
  64. package/dist/vite/extractProps.js +79 -0
  65. package/dist/vite/index.d.ts +18 -0
  66. package/dist/vite/index.d.ts.map +1 -0
  67. package/dist/vite/index.js +73 -0
  68. package/package.json +111 -4
@@ -0,0 +1,156 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Top bar search — filters the docs navigation and jumps to the selected page (⌘K / Ctrl+K) */
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
+ import { useNavigate } from 'react-router-dom';
5
+ import { MagnifyingGlass } from '@phosphor-icons/react';
6
+ import { useNav } from '../../app/config';
7
+ const IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);
8
+ const S = {
9
+ wrapper: { position: 'relative', width: 280 },
10
+ field: (focused) => ({
11
+ display: 'flex',
12
+ alignItems: 'center',
13
+ gap: 8,
14
+ height: 34,
15
+ padding: '0 10px',
16
+ backgroundColor: 'var(--docs-surface)',
17
+ border: `1px solid ${focused ? 'var(--docs-accent)' : 'var(--docs-border)'}`,
18
+ borderRadius: 8,
19
+ transition: 'border-color 0.15s',
20
+ }),
21
+ icon: { color: 'var(--docs-text-muted)', flexShrink: 0 },
22
+ input: {
23
+ flex: 1,
24
+ minWidth: 0,
25
+ border: 'none',
26
+ background: 'transparent',
27
+ outline: 'none',
28
+ fontFamily: 'inherit',
29
+ fontSize: 13,
30
+ color: 'var(--docs-text-primary)',
31
+ },
32
+ kbd: {
33
+ fontFamily: 'inherit',
34
+ fontSize: 11,
35
+ color: 'var(--docs-text-muted)',
36
+ border: '1px solid var(--docs-border)',
37
+ borderRadius: 4,
38
+ padding: '0 5px',
39
+ lineHeight: '18px',
40
+ flexShrink: 0,
41
+ },
42
+ dropdown: {
43
+ position: 'absolute',
44
+ top: 'calc(100% + 6px)',
45
+ left: 0,
46
+ right: 0,
47
+ maxHeight: 360,
48
+ overflowY: 'auto',
49
+ backgroundColor: 'var(--docs-bg)',
50
+ border: '1px solid var(--docs-border)',
51
+ borderRadius: 8,
52
+ boxShadow: 'var(--docs-shadow-md)',
53
+ padding: 4,
54
+ listStyle: 'none',
55
+ },
56
+ option: (active) => ({
57
+ display: 'flex',
58
+ alignItems: 'center',
59
+ justifyContent: 'space-between',
60
+ gap: 8,
61
+ padding: '7px 10px',
62
+ borderRadius: 6,
63
+ cursor: 'pointer',
64
+ fontSize: 13,
65
+ color: active ? 'var(--docs-accent)' : 'var(--docs-text-primary)',
66
+ backgroundColor: active ? 'var(--docs-accent-subtle)' : 'transparent',
67
+ }),
68
+ optionGroup: { fontSize: 11, color: 'var(--docs-text-muted)' },
69
+ empty: { padding: '10px', fontSize: 13, color: 'var(--docs-text-muted)' },
70
+ };
71
+ export default function ComponentSearch() {
72
+ const navigate = useNavigate();
73
+ const inputRef = useRef(null);
74
+ const wrapperRef = useRef(null);
75
+ const listRef = useRef(null);
76
+ const [query, setQuery] = useState('');
77
+ const [open, setOpen] = useState(false);
78
+ const [focused, setFocused] = useState(false);
79
+ const [activeIndex, setActiveIndex] = useState(0);
80
+ const nav = useNav();
81
+ const allItems = useMemo(() => nav.flatMap(({ group, items }) => items.map((item) => ({ ...item, group }))), [nav]);
82
+ const results = useMemo(() => {
83
+ const q = query.trim().toLowerCase();
84
+ if (!q)
85
+ return allItems;
86
+ // Prefix matches first, then substring matches
87
+ const matches = allItems.filter((item) => item.label.toLowerCase().includes(q));
88
+ return matches.sort((a, b) => Number(!a.label.toLowerCase().startsWith(q)) - Number(!b.label.toLowerCase().startsWith(q)));
89
+ }, [query, allItems]);
90
+ // Global ⌘K / Ctrl+K shortcut focuses the search
91
+ useEffect(() => {
92
+ const onKeyDown = (e) => {
93
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
94
+ e.preventDefault();
95
+ inputRef.current?.focus();
96
+ inputRef.current?.select();
97
+ setOpen(true);
98
+ }
99
+ };
100
+ window.addEventListener('keydown', onKeyDown);
101
+ return () => window.removeEventListener('keydown', onKeyDown);
102
+ }, []);
103
+ // Close the dropdown on outside click
104
+ useEffect(() => {
105
+ const onMouseDown = (e) => {
106
+ if (!wrapperRef.current?.contains(e.target))
107
+ setOpen(false);
108
+ };
109
+ document.addEventListener('mousedown', onMouseDown);
110
+ return () => document.removeEventListener('mousedown', onMouseDown);
111
+ }, []);
112
+ // Keep the highlighted option visible while navigating with arrows
113
+ useEffect(() => {
114
+ const el = listRef.current?.children[activeIndex];
115
+ el?.scrollIntoView({ block: 'nearest' });
116
+ }, [activeIndex]);
117
+ const select = (item) => {
118
+ navigate(item.path);
119
+ setQuery('');
120
+ setOpen(false);
121
+ inputRef.current?.blur();
122
+ };
123
+ const onKeyDown = (e) => {
124
+ if (e.key === 'ArrowDown') {
125
+ e.preventDefault();
126
+ setOpen(true);
127
+ setActiveIndex((i) => Math.min(i + 1, results.length - 1));
128
+ }
129
+ else if (e.key === 'ArrowUp') {
130
+ e.preventDefault();
131
+ setActiveIndex((i) => Math.max(i - 1, 0));
132
+ }
133
+ else if (e.key === 'Enter') {
134
+ const item = results[activeIndex];
135
+ if (item)
136
+ select(item);
137
+ }
138
+ else if (e.key === 'Escape') {
139
+ setOpen(false);
140
+ inputRef.current?.blur();
141
+ }
142
+ };
143
+ return (_jsxs("div", { ref: wrapperRef, style: S.wrapper, children: [_jsxs("div", { style: S.field(focused), onClick: () => inputRef.current?.focus(), children: [_jsx(MagnifyingGlass, { size: 15, style: S.icon }), _jsx("input", { ref: inputRef, type: "text", value: query, placeholder: "Rechercher un composant\u2026", "aria-label": "Rechercher un composant", role: "combobox", "aria-expanded": open, "aria-controls": "component-search-results", "aria-activedescendant": open && results[activeIndex] ? `search-opt-${activeIndex}` : undefined, style: S.input, onChange: (e) => {
144
+ setQuery(e.target.value);
145
+ setActiveIndex(0);
146
+ setOpen(true);
147
+ }, onFocus: () => {
148
+ setFocused(true);
149
+ setOpen(true);
150
+ }, onBlur: () => setFocused(false), onKeyDown: onKeyDown }), !focused && _jsx("kbd", { style: S.kbd, children: IS_MAC ? '⌘K' : 'Ctrl K' })] }), open && (_jsx("ul", { id: "component-search-results", role: "listbox", ref: listRef, style: S.dropdown, children: results.length === 0 ? (_jsx("li", { style: S.empty, children: "Aucun r\u00E9sultat" })) : (results.map((item, i) => (_jsxs("li", { id: `search-opt-${i}`, role: "option", "aria-selected": i === activeIndex, style: S.option(i === activeIndex), onMouseEnter: () => setActiveIndex(i),
151
+ // mousedown instead of click so the input blur doesn't swallow the selection
152
+ onMouseDown: (e) => {
153
+ e.preventDefault();
154
+ select(item);
155
+ }, children: [_jsx("span", { children: item.label }), _jsx("span", { style: S.optionGroup, children: item.group })] }, item.path)))) }))] }));
156
+ }
@@ -0,0 +1,8 @@
1
+ /** Doc site shell: fixed sidebar + glassmorphism top bar + main content */
2
+ import type { ReactNode } from 'react';
3
+ interface LayoutProps {
4
+ children: ReactNode;
5
+ }
6
+ export default function Layout({ children }: LayoutProps): import("react").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=Layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Layout.tsx"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAQtC,UAAU,WAAW;IACnB,QAAQ,EAAE,SAAS,CAAA;CACpB;AA+GD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW,+BAuCvD"}
@@ -0,0 +1,109 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import Sidebar from './Sidebar';
3
+ import ComponentSearch from './ComponentSearch';
4
+ import { Link } from 'react-router-dom';
5
+ import { useColorMode } from '../../app/ColorModeContext';
6
+ import { useDocsConfig } from '../../app/config';
7
+ const TOP_BAR_HEIGHT = 52;
8
+ const S = {
9
+ root: { display: 'flex', minHeight: '100vh' },
10
+ sidebar: {
11
+ width: 240,
12
+ flexShrink: 0,
13
+ backgroundColor: '#0c0f1a',
14
+ position: 'fixed',
15
+ top: 0,
16
+ left: 0,
17
+ bottom: 0,
18
+ overflowY: 'auto',
19
+ zIndex: 100,
20
+ },
21
+ topBar: {
22
+ position: 'fixed',
23
+ top: 0,
24
+ left: 240,
25
+ right: 0,
26
+ height: TOP_BAR_HEIGHT,
27
+ backgroundColor: 'rgba(var(--docs-bg-rgb, 255,255,255), 0.85)',
28
+ backdropFilter: 'blur(12px)',
29
+ WebkitBackdropFilter: 'blur(12px)',
30
+ borderBottom: '1px solid var(--docs-border)',
31
+ display: 'flex',
32
+ alignItems: 'center',
33
+ justifyContent: 'space-between',
34
+ padding: '0 28px',
35
+ zIndex: 99,
36
+ gap: 10,
37
+ transition: 'border-color 0.2s',
38
+ },
39
+ actions: {
40
+ display: 'flex',
41
+ alignItems: 'center',
42
+ gap: 20,
43
+ },
44
+ links: {
45
+ display: 'flex',
46
+ alignItems: 'center',
47
+ gap: 16,
48
+ },
49
+ link: {
50
+ fontSize: 13,
51
+ fontWeight: 500,
52
+ color: 'var(--docs-text-secondary)',
53
+ textDecoration: 'none',
54
+ whiteSpace: 'nowrap',
55
+ },
56
+ themeSwitch: {
57
+ display: 'flex',
58
+ alignItems: 'center',
59
+ gap: 10,
60
+ },
61
+ modeLabel: {
62
+ fontSize: 12,
63
+ color: 'var(--docs-text-muted)',
64
+ fontWeight: 500,
65
+ },
66
+ segmented: {
67
+ display: 'flex',
68
+ backgroundColor: 'var(--docs-surface)',
69
+ border: '1px solid var(--docs-border)',
70
+ borderRadius: 8,
71
+ padding: 2,
72
+ gap: 2,
73
+ },
74
+ segBtn: (active) => ({
75
+ fontSize: 12,
76
+ fontWeight: active ? 600 : 400,
77
+ padding: '4px 12px',
78
+ border: 'none',
79
+ borderRadius: 6,
80
+ cursor: 'pointer',
81
+ backgroundColor: active ? 'var(--docs-bg)' : 'transparent',
82
+ color: active ? 'var(--docs-text-primary)' : 'var(--docs-text-muted)',
83
+ boxShadow: active ? 'var(--docs-shadow-sm)' : 'none',
84
+ transition: 'all 0.15s',
85
+ }),
86
+ main: {
87
+ marginLeft: 240,
88
+ flex: 1,
89
+ // Flex items default to min-width: auto: wide content (browser frame, tables) would push the page sideways
90
+ minWidth: 0,
91
+ backgroundColor: 'var(--docs-bg)',
92
+ minHeight: '100vh',
93
+ paddingTop: TOP_BAR_HEIGHT,
94
+ transition: 'background 0.2s',
95
+ },
96
+ content: {
97
+ maxWidth: 1100,
98
+ padding: '52px 48px',
99
+ },
100
+ };
101
+ function TopBarLink({ label, href }) {
102
+ // Absolute URLs leave the docs; paths stay in the single-page app
103
+ return /^https?:\/\//.test(href) ? (_jsxs("a", { href: href, target: "_blank", rel: "noreferrer", style: S.link, children: [label, " \u2197"] })) : (_jsx(Link, { to: href, style: S.link, children: label }));
104
+ }
105
+ export default function Layout({ children }) {
106
+ const { mode, setMode } = useColorMode();
107
+ const { links } = useDocsConfig();
108
+ return (_jsxs("div", { style: S.root, children: [_jsx("aside", { style: S.sidebar, children: _jsx(Sidebar, {}) }), _jsxs("div", { style: S.topBar, children: [_jsx(ComponentSearch, {}), _jsxs("div", { style: S.actions, children: [links && links.length > 0 && (_jsx("nav", { style: S.links, "aria-label": "Liens", children: links.map((link) => (_jsx(TopBarLink, { ...link }, link.href))) })), _jsxs("div", { style: S.themeSwitch, children: [_jsx("span", { style: S.modeLabel, children: "Th\u00E8me" }), _jsxs("div", { style: S.segmented, children: [_jsx("button", { style: S.segBtn(mode === 'light'), "aria-pressed": mode === 'light', onClick: () => setMode('light'), children: "\u2600 Light" }), _jsx("button", { style: S.segBtn(mode === 'dark'), "aria-pressed": mode === 'dark', onClick: () => setMode('dark'), children: "\uD83C\uDF19 Dark" })] })] })] })] }), _jsx("main", { style: S.main, children: _jsx("div", { style: S.content, children: children }) })] }));
109
+ }
@@ -0,0 +1,2 @@
1
+ export default function NotFound(): import("react").JSX.Element;
2
+ //# sourceMappingURL=NotFound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotFound.d.ts","sourceRoot":"","sources":["../../../src/components/layout/NotFound.tsx"],"names":[],"mappings":"AAkCA,MAAM,CAAC,OAAO,UAAU,QAAQ,gCAW/B"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Fallback page for unknown routes */
3
+ import { Link } from 'react-router-dom';
4
+ const S = {
5
+ root: { padding: '48px 0', maxWidth: 560 },
6
+ code: {
7
+ fontSize: 13,
8
+ fontWeight: 600,
9
+ color: 'var(--docs-text-muted)',
10
+ letterSpacing: '0.1em',
11
+ textTransform: 'uppercase',
12
+ },
13
+ title: {
14
+ fontSize: 32,
15
+ fontWeight: 700,
16
+ lineHeight: 1.2,
17
+ margin: '8px 0 12px',
18
+ color: 'var(--docs-text-primary)',
19
+ letterSpacing: '-0.02em',
20
+ },
21
+ text: { color: 'var(--docs-text-secondary)', marginBottom: 24 },
22
+ link: {
23
+ display: 'inline-block',
24
+ fontSize: 14,
25
+ fontWeight: 600,
26
+ color: 'var(--docs-text-primary)',
27
+ backgroundColor: 'var(--docs-surface)',
28
+ border: '1px solid var(--docs-border)',
29
+ borderRadius: 8,
30
+ padding: '8px 16px',
31
+ textDecoration: 'none',
32
+ },
33
+ };
34
+ export default function NotFound() {
35
+ return (_jsxs("div", { style: S.root, children: [_jsx("span", { style: S.code, children: "Erreur 404" }), _jsx("h1", { style: S.title, children: "Page introuvable" }), _jsx("p", { style: S.text, children: "Cette page n'existe pas ou a \u00E9t\u00E9 d\u00E9plac\u00E9e. Utilise la recherche ou la navigation \u00E0 gauche." }), _jsx(Link, { to: "/", style: S.link, children: "Retour \u00E0 l'accueil" })] }));
36
+ }
@@ -0,0 +1,2 @@
1
+ export default function Sidebar(): import("react").JSX.Element;
2
+ //# sourceMappingURL=Sidebar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Sidebar.tsx"],"names":[],"mappings":"AAiFA,MAAM,CAAC,OAAO,UAAU,OAAO,gCAwC9B"}
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Navigation sidebar — always dark, pill-style active states */
3
+ import { useState } from 'react';
4
+ import { NavLink } from 'react-router-dom';
5
+ import { useDocsConfig, useNav } from '../../app/config';
6
+ const S = {
7
+ container: {
8
+ padding: '20px 0 24px',
9
+ height: '100%',
10
+ display: 'flex',
11
+ flexDirection: 'column',
12
+ },
13
+ brand: {
14
+ display: 'flex',
15
+ alignItems: 'center',
16
+ gap: 10,
17
+ color: '#fff',
18
+ fontSize: 15,
19
+ fontWeight: 700,
20
+ padding: '0 16px 16px',
21
+ marginBottom: 8,
22
+ textDecoration: 'none',
23
+ letterSpacing: '-0.01em',
24
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
25
+ },
26
+ brandSub: {
27
+ display: 'block',
28
+ fontSize: 11,
29
+ color: 'rgba(255,255,255,0.4)',
30
+ fontWeight: 400,
31
+ marginTop: 2,
32
+ },
33
+ // Bounded box: wide wordmarks shrink to fit instead of overflowing the sidebar
34
+ logo: {
35
+ display: 'block',
36
+ height: 28,
37
+ width: 'auto',
38
+ maxWidth: 96,
39
+ objectFit: 'contain',
40
+ objectPosition: 'left center',
41
+ flexShrink: 0,
42
+ },
43
+ brandText: { minWidth: 0, overflowWrap: 'anywhere' },
44
+ footer: {
45
+ // Pushed to the bottom of the sidebar, below the navigation
46
+ marginTop: 'auto',
47
+ padding: '16px 16px 0',
48
+ borderTop: '1px solid rgba(255,255,255,0.08)',
49
+ fontSize: 11,
50
+ fontWeight: 500,
51
+ color: 'rgba(255,255,255,0.4)',
52
+ letterSpacing: '0.02em',
53
+ },
54
+ group: { marginTop: 16, paddingBottom: 8 },
55
+ groupLabel: {
56
+ display: 'block',
57
+ color: 'rgba(255,255,255,0.3)',
58
+ fontSize: 10,
59
+ fontWeight: 600,
60
+ letterSpacing: '0.1em',
61
+ textTransform: 'uppercase',
62
+ padding: '0 16px 6px',
63
+ },
64
+ link: (active, hovered) => ({
65
+ display: 'block',
66
+ padding: '6px 12px',
67
+ margin: '1px 8px',
68
+ color: active ? '#fff' : hovered ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.55)',
69
+ textDecoration: 'none',
70
+ fontSize: 14,
71
+ fontWeight: active ? 500 : 400,
72
+ borderRadius: 6,
73
+ backgroundColor: active
74
+ ? 'rgba(255,255,255,0.1)'
75
+ : hovered
76
+ ? 'rgba(255,255,255,0.05)'
77
+ : 'transparent',
78
+ transition: 'background 0.15s, color 0.15s',
79
+ }),
80
+ };
81
+ export default function Sidebar() {
82
+ const [hovered, setHovered] = useState(null);
83
+ const { brand } = useDocsConfig();
84
+ // Without a logo the name is the only identity: always shown
85
+ const showName = !brand.logo || brand.showName !== false;
86
+ const nav = useNav();
87
+ return (_jsxs("div", { style: S.container, children: [_jsxs(NavLink, { to: "/", style: S.brand, children: [brand.logo && _jsx("img", { src: brand.logo, alt: showName ? '' : brand.name, style: S.logo }), (showName || brand.subtitle) && (_jsxs("span", { style: S.brandText, children: [showName && brand.name, brand.subtitle && _jsx("span", { style: S.brandSub, children: brand.subtitle })] }))] }), nav.map(({ group, items }) => (_jsxs("div", { style: S.group, children: [_jsx("span", { style: S.groupLabel, children: group }), items.map(({ label, path }) => (_jsx(NavLink, { to: path, style: ({ isActive }) => S.link(isActive, hovered === path), onMouseEnter: () => setHovered(path), onMouseLeave: () => setHovered(null), children: label }, path)))] }, group))), brand.version && _jsxs("div", { style: S.footer, children: ["v", brand.version] })] }));
88
+ }
@@ -0,0 +1,10 @@
1
+ export interface TocItem {
2
+ id: string;
3
+ label: string;
4
+ }
5
+ interface TableOfContentsProps {
6
+ items: TocItem[];
7
+ }
8
+ export default function TableOfContents({ items }: TableOfContentsProps): import("react").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=TableOfContents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableOfContents.d.ts","sourceRoot":"","sources":["../../../src/components/layout/TableOfContents.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,oBAAoB;IAC5B,KAAK,EAAE,OAAO,EAAE,CAAA;CACjB;AA+BD,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,oBAAoB,+BAiCtE"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Sticky right-side table of contents with active section tracking */
3
+ import { useState, useEffect } from 'react';
4
+ const S = {
5
+ container: {
6
+ width: 200,
7
+ flexShrink: 0,
8
+ position: 'sticky',
9
+ top: 80,
10
+ alignSelf: 'flex-start',
11
+ },
12
+ heading: {
13
+ fontSize: 11,
14
+ fontWeight: 700,
15
+ letterSpacing: '0.08em',
16
+ textTransform: 'uppercase',
17
+ color: 'var(--docs-text-muted)',
18
+ marginBottom: 12,
19
+ },
20
+ link: (active) => ({
21
+ display: 'block',
22
+ fontSize: 13,
23
+ padding: '4px 0 4px 12px',
24
+ color: active ? 'var(--docs-accent)' : 'var(--docs-text-muted)',
25
+ textDecoration: 'none',
26
+ borderLeft: `2px solid ${active ? 'var(--docs-accent)' : 'var(--docs-border)'}`,
27
+ marginBottom: 2,
28
+ fontWeight: active ? 600 : 400,
29
+ transition: 'color 0.15s, border-color 0.15s',
30
+ }),
31
+ };
32
+ export default function TableOfContents({ items }) {
33
+ const [activeId, setActiveId] = useState(items[0]?.id ?? '');
34
+ useEffect(() => {
35
+ const observer = new IntersectionObserver((entries) => {
36
+ const visible = entries.filter((e) => e.isIntersecting);
37
+ if (visible.length > 0)
38
+ setActiveId(visible[0].target.id);
39
+ }, { rootMargin: '-10% 0% -70% 0%', threshold: 0 });
40
+ items.forEach(({ id }) => {
41
+ const el = document.getElementById(id);
42
+ if (el)
43
+ observer.observe(el);
44
+ });
45
+ return () => observer.disconnect();
46
+ }, [items]);
47
+ return (_jsxs("nav", { style: S.container, children: [_jsx("p", { style: S.heading, children: "Sur cette page" }), items.map(({ id, label }) => (_jsx("a", { href: `#${id}`, style: S.link(activeId === id), onClick: () => setActiveId(id), children: label }, id)))] }));
48
+ }
@@ -0,0 +1,5 @@
1
+ export declare function useCopy(feedbackMs?: number): {
2
+ copied: boolean;
3
+ copy: (text: string) => void;
4
+ };
5
+ //# sourceMappingURL=useCopy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCopy.d.ts","sourceRoot":"","sources":["../../src/hooks/useCopy.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,CAAC,UAAU,SAAO;;iBAO9B,MAAM;EAehB"}
@@ -0,0 +1,19 @@
1
+ /** Copy to clipboard with a short "copied" feedback state */
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ export function useCopy(feedbackMs = 2000) {
4
+ const [copied, setCopied] = useState(false);
5
+ const timer = useRef(undefined);
6
+ useEffect(() => () => clearTimeout(timer.current), []);
7
+ const copy = useCallback((text) => {
8
+ // Clipboard is unavailable on insecure origins: fail silently, the text stays selectable
9
+ navigator.clipboard
10
+ ?.writeText(text)
11
+ .then(() => {
12
+ setCopied(true);
13
+ clearTimeout(timer.current);
14
+ timer.current = setTimeout(() => setCopied(false), feedbackMs);
15
+ })
16
+ .catch(() => { });
17
+ }, [feedbackMs]);
18
+ return { copied, copy };
19
+ }
@@ -0,0 +1,21 @@
1
+ /** Public API of @situaction/traquiste-docs-kit */
2
+ export { createDocsApp, DocsApp } from './app/createDocsApp';
3
+ export { defineDocsConfig, useDocsConfig } from './app/config';
4
+ export type { ColorMode, DocsConfig, DocsLink, DocsPage, DocsWrapper, NavGroup, NavItem } from './app/config';
5
+ export { createComponentPage } from './pages/createComponentPage';
6
+ export type { ComponentPageConfig, ComponentStatus, Demo, PropDef } from './pages/createComponentPage';
7
+ export type { ComponentProps } from './components/PropsTable';
8
+ export { createScreenPage } from './pages/createScreenPage';
9
+ export type { ScreenConfig, ScreenPageConfig } from './pages/createScreenPage';
10
+ export { DeviceFrame } from './components/DeviceFrame';
11
+ export type { DeviceFrameProps, DeviceType } from './components/DeviceFrame';
12
+ export { default as LiveEditor } from './components/LiveEditor';
13
+ export { DocPage, DocSection } from './pages/DocPage';
14
+ export type { DocPageProps, DocSectionProps } from './pages/DocPage';
15
+ export { CodeBlock } from './components/CodeBlock';
16
+ export type { CodeBlockProps } from './components/CodeBlock';
17
+ export { Callout } from './components/Callout';
18
+ export { Link } from 'react-router-dom';
19
+ export type { CalloutProps, CalloutType } from './components/Callout';
20
+ export { useColorMode } from './app/ColorModeContext';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACtG,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE5E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACrD,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAE9C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /** Public API of @situaction/traquiste-docs-kit */
2
+ export { createDocsApp, DocsApp } from './app/createDocsApp';
3
+ export { defineDocsConfig, useDocsConfig } from './app/config';
4
+ export { createComponentPage } from './pages/createComponentPage';
5
+ export { createScreenPage } from './pages/createScreenPage';
6
+ export { DeviceFrame } from './components/DeviceFrame';
7
+ export { default as LiveEditor } from './components/LiveEditor';
8
+ export { DocPage, DocSection } from './pages/DocPage';
9
+ export { CodeBlock } from './components/CodeBlock';
10
+ export { Callout } from './components/Callout';
11
+ // In-site links for guide pages, without a full reload — the docs' own router instance
12
+ export { Link } from 'react-router-dom';
13
+ export { useColorMode } from './app/ColorModeContext';
@@ -0,0 +1,26 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface DocPageProps {
3
+ /** Page title (H1) */
4
+ title: string;
5
+ /** Lead paragraph under the title */
6
+ description?: ReactNode;
7
+ /** Page content — use DocSection for headings listed in the table of contents */
8
+ children: ReactNode;
9
+ }
10
+ export interface DocSectionProps {
11
+ /** Section heading (H2), also shown in the table of contents */
12
+ title: string;
13
+ /** Anchor id — defaults to the slugified title */
14
+ id?: string;
15
+ /** Lead paragraph under the heading */
16
+ description?: ReactNode;
17
+ children?: ReactNode;
18
+ }
19
+ /** H2 section of a guide page */
20
+ export declare function DocSection({ title, id, description, children }: DocSectionProps): import("react").JSX.Element;
21
+ /** Guide page (Getting started, Theming…) with the same layout as component pages */
22
+ export declare function DocPage({ title, description, children }: DocPageProps): import("react").JSX.Element;
23
+ export declare namespace DocPage {
24
+ var Section: typeof DocSection;
25
+ }
26
+ //# sourceMappingURL=DocPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocPage.d.ts","sourceRoot":"","sources":["../../src/pages/DocPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,WAAW,YAAY;IAC3B,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,qCAAqC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,iFAAiF;IACjF,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,uCAAuC;IACvC,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAKD,iCAAiC;AACjC,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,eAAe,+BAU/E;AAED,qFAAqF;AACrF,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,YAAY,+BAsBrE;yBAtBe,OAAO"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Guide page: title, description, sections and an automatic table of contents */
3
+ import { useLayoutEffect, useRef, useState } from 'react';
4
+ import TableOfContents from '../components/layout/TableOfContents';
5
+ import { pageStyles as S, slugify } from '../styles/pageStyles';
6
+ const sameItems = (a, b) => a.length === b.length && a.every((item, i) => item.id === b[i].id && item.label === b[i].label);
7
+ /** H2 section of a guide page */
8
+ export function DocSection({ title, id, description, children }) {
9
+ return (_jsxs("section", { children: [_jsx("h2", { id: id ?? slugify(title), "data-doc-section": title, style: S.sectionHeading, children: title }), description && _jsx("p", { style: S.sectionDescription, children: description }), children] }));
10
+ }
11
+ /** Guide page (Getting started, Theming…) with the same layout as component pages */
12
+ export function DocPage({ title, description, children }) {
13
+ const contentRef = useRef(null);
14
+ const [toc, setToc] = useState([]);
15
+ // Read the sections from the DOM: they can be nested in fragments or custom components
16
+ useLayoutEffect(() => {
17
+ const headings = contentRef.current?.querySelectorAll('h2[data-doc-section]') ?? [];
18
+ const items = [...headings].map((h) => ({ id: h.id, label: h.dataset.docSection ?? '' }));
19
+ setToc((prev) => (sameItems(prev, items) ? prev : items));
20
+ }, [children]);
21
+ return (_jsxs("div", { style: S.layout, children: [_jsxs("div", { ref: contentRef, className: "docs-prose", style: S.content, children: [_jsx("h1", { style: S.title, children: title }), description && _jsx("p", { style: S.description, children: description }), children] }), toc.length > 0 && _jsx(TableOfContents, { items: toc })] }));
22
+ }
23
+ DocPage.Section = DocSection;
@@ -0,0 +1,33 @@
1
+ import type { PropDef } from '../components/PropsTable';
2
+ export type { PropDef };
3
+ export interface Demo {
4
+ /** Optional H2 section heading rendered above this demo */
5
+ section?: string;
6
+ /** Optional description rendered below the section heading */
7
+ sectionDescription?: string;
8
+ /** Label shown in the demo card header */
9
+ title: string;
10
+ /** JSX expression shown and evaluated live */
11
+ code: string;
12
+ /** Wrap preview in a phone frame (for full-width mobile components) */
13
+ phoneFrame?: boolean;
14
+ }
15
+ /** 'updated': an existing component changed in a recent release */
16
+ export type ComponentStatus = 'stable' | 'beta' | 'new' | 'updated' | 'deprecated';
17
+ export interface ComponentPageConfig {
18
+ title: string;
19
+ description: string;
20
+ /** Maturity status of the component */
21
+ status?: ComponentStatus;
22
+ /** Link to the Figma component (opens in a new tab) */
23
+ figma?: string;
24
+ /** Components available in the live editor. React is injected automatically. */
25
+ scope: Record<string, unknown>;
26
+ demos: Demo[];
27
+ /** Props table: written by hand, or 'auto' to read it from the component's TypeScript source (docgen plugin) */
28
+ props: PropDef[] | 'auto';
29
+ /** Component whose props are shown with `props: 'auto'` — defaults to `title` */
30
+ propsOf?: string;
31
+ }
32
+ export declare function createComponentPage(config: ComponentPageConfig): () => import("react").JSX.Element;
33
+ //# sourceMappingURL=createComponentPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createComponentPage.d.ts","sourceRoot":"","sources":["../../src/pages/createComponentPage.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAGvD,YAAY,EAAE,OAAO,EAAE,CAAA;AAEvB,MAAM,WAAW,IAAI;IACnB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,CAAA;AAElF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,gHAAgH;IAChH,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,CAAA;IACzB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AA6JD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,qCAiE9D"}