@docpensieve/components 0.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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Card and its parts.
3
+ *
4
+ * The component provides the **structure** — the wrapper, the separators, the
5
+ * spacing. The look is set through `className`, with the utilities of the
6
+ * active theme. One prop per typographic setting would mean reimplementing,
7
+ * less well, what CSS already does.
8
+ *
9
+ * Classes come from the theme (ADR-007), never from a hard-coded framework.
10
+ *
11
+ * The files of this package are plain JavaScript, with no build step: no JSX,
12
+ * hence `createElement` — shortened to `h` for readability.
13
+ *
14
+ * @module @docpensieve/components/card
15
+ */
16
+ export type PartProps = {
17
+ /**
18
+ * Classes added to the component's own.
19
+ */
20
+ className?: string;
21
+ style?: object;
22
+ children?: any;
23
+ };
24
+ /**
25
+ * Card container.
26
+ *
27
+ * @param {PartProps & { elevated?: boolean, href?: string }} props
28
+ * `elevated` adds a shadow. `href` makes the whole card clickable, rather
29
+ * than a link on the title alone that would leave the rest inert.
30
+ */
31
+ export declare function Card({ className, style, children, elevated, href }: PartProps & {
32
+ elevated?: boolean;
33
+ href?: string;
34
+ }): import("react").DetailedReactHTMLElement<{
35
+ className: string | undefined;
36
+ style: object | undefined;
37
+ href?: string | undefined;
38
+ }, HTMLElement>;
39
+ export declare const CardHeader: (props: PartProps) => any;
40
+ export declare const CardBody: (props: PartProps) => any;
41
+ export declare const CardFooter: (props: PartProps) => any;
42
+ /**
43
+ * Image at the top of a card.
44
+ *
45
+ * `src` resolves as in Markdown — relative to the page, absolute from the
46
+ * version root. The compiler plugins cannot handle it: they work on the
47
+ * Markdown tree, before React renders anything. So the component does it
48
+ * itself (ADR-006).
49
+ *
50
+ * @param {{
51
+ * className?: string, style?: object, src?: string,
52
+ * alt?: string, title?: string, srcSet?: string, sizes?: string,
53
+ * }} props `alt` defaults to the empty string: without that attribute, a
54
+ * screen reader would announce the file URL.
55
+ */
56
+ export declare function CardImage({ className, style, src, alt, ...rest }: {
57
+ className?: string;
58
+ style?: object;
59
+ src?: string;
60
+ alt?: string;
61
+ title?: string;
62
+ srcSet?: string;
63
+ sizes?: string;
64
+ }): import("react").DetailedReactHTMLElement<{
65
+ title?: string;
66
+ srcSet?: string;
67
+ sizes?: string;
68
+ className: string | undefined;
69
+ style: object | undefined;
70
+ src: string | undefined;
71
+ alt: string;
72
+ }, HTMLElement>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Resolution of component classes.
3
+ *
4
+ * A component never writes a framework class. It asks for the class of its
5
+ * slot, and the theme answers — or not. Without an answer, the fallback is a
6
+ * `dp-*` class that the package stylesheet styles on the `--dp-*` tokens: the
7
+ * component therefore follows the active palette without knowing anything
8
+ * about it (ADR-007).
9
+ *
10
+ * @module @docpensieve/components/classes
11
+ */
12
+ /**
13
+ * Declares the theme table for the whole compilation.
14
+ *
15
+ * @param {Record<string, string>} [classes]
16
+ */
17
+ export declare function setThemeClasses(classes?: Record<string, string>): void;
18
+ /** @returns {Record<string, string>} The current table, for inspection. */
19
+ export declare function getThemeClasses(): Record<string, string>;
20
+ /**
21
+ * Converts a slot name into a fallback class.
22
+ *
23
+ * @example
24
+ * fallbackClass('cardHeader') // 'dp-card-header'
25
+ *
26
+ * @param {string} slot
27
+ * @returns {string}
28
+ */
29
+ export declare function fallbackClass(slot: string): string;
30
+ /**
31
+ * Class of a slot, variants included.
32
+ *
33
+ * @example
34
+ * cls('card') // 'dp-card'
35
+ * cls('card', 'shadow') // 'dp-card dp-card--shadow'
36
+ * cls('alert', false && 'x') // 'dp-alert' — falsy values are ignored
37
+ *
38
+ * @param {string} slot Slot name.
39
+ * @param {...unknown} modifiers Variants, each one suffixed as `--variant`.
40
+ * Falsy values are ignored, which allows writing `cls('card', shadow && shadow)`.
41
+ * @returns {string}
42
+ */
43
+ export declare function cls(slot: string, ...modifiers: unknown[]): string;
44
+ /**
45
+ * Joins classes while ignoring falsy values.
46
+ *
47
+ * A minimal equivalent of `clsx`: one more dependency is not worth it for six
48
+ * lines.
49
+ *
50
+ * @param {...unknown} parts
51
+ * @returns {string | undefined} `undefined` when nothing is left, to avoid a
52
+ * `class=""` in the produced HTML.
53
+ */
54
+ export declare function classNames(...parts: unknown[]): string | undefined;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Column grid.
3
+ *
4
+ * Not to be confused with CSS multi-column (`column-count`), where content
5
+ * *flows* from one column to the next as in a newspaper. Here every block is
6
+ * placed explicitly: it is a grid, not a flow. For a flow, the theme's
7
+ * utilities are enough, without a component.
8
+ *
9
+ * Two layouts, depending on what the row holds:
10
+ *
11
+ * - **no declared width** — the columns share the space equally, whatever
12
+ * their number;
13
+ * - **declared widths** — twelve tracks, and each column takes the number it
14
+ * asks for.
15
+ *
16
+ * The grid works out the gap between columns by itself: a width therefore has
17
+ * no calculation to make, and changing the gap breaks nothing.
18
+ *
19
+ * Classes come from the theme (ADR-007), never from a hard-coded framework.
20
+ *
21
+ * @module @docpensieve/components/columns
22
+ */
23
+ /**
24
+ * Row of columns.
25
+ *
26
+ * The gap is set through `className` or `style`, with the theme's utilities:
27
+ * the grid recomputes the widths by itself.
28
+ *
29
+ * @param {{ className?: string, style?: object, children?: any }} props
30
+ */
31
+ export declare function Columns({ className, style, children }: {
32
+ className?: string;
33
+ style?: object;
34
+ children?: any;
35
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<{
36
+ sized: boolean;
37
+ } | null>>;
38
+ /**
39
+ * Column of a row.
40
+ *
41
+ * @param {{ className?: string, style?: object, children?: any, span?: number }} props
42
+ * `span` is the number of tracks taken out of twelve — `span={6}` for a
43
+ * half, `span={8}` for two thirds. Twelve because twelve divides by two,
44
+ * three, four and six. Without `span`, the columns share the space equally.
45
+ * @throws {DocPensieveError} Outside a `Columns`, or when the row mixes
46
+ * columns with and without a width.
47
+ */
48
+ export declare function Column({ className, style, children, span }: {
49
+ className?: string;
50
+ style?: object;
51
+ children?: any;
52
+ span?: number;
53
+ }): import("react").DetailedReactHTMLElement<{
54
+ className: string | undefined;
55
+ style: object | undefined;
56
+ }, HTMLElement>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @docpensieve/components — global components available in MDX.
3
+ *
4
+ * React is a build-only dependency: the generated HTML loads no React
5
+ * runtime. The components are therefore **static** — no state, no event
6
+ * listener. Whatever needs interaction goes through CSS or through native
7
+ * HTML elements such as `<details>`.
8
+ *
9
+ * @module @docpensieve/components
10
+ */
11
+ export { classNames, cls, fallbackClass, getThemeClasses, setThemeClasses } from './classes.js';
12
+ export { Card, CardBody, CardFooter, CardHeader, CardImage } from './card.js';
13
+ export { Column, Columns } from './columns.js';
14
+ export { FallbackAfter, FallbackBefore, TimeTimer } from './time-timer.js';
15
+ export { TOOLTIP_PLACEMENTS, Tooltip } from './tooltip.js';
16
+ export { Tree, TreeItem } from './tree.js';
17
+ export { ScrollToTop } from './scroll-to-top.js';
18
+ export { SKILL_SHAPES, Skill } from './skill.js';
19
+ export { LogoIcon } from './logo-icon.js';
20
+ export { componentsCss } from './styles.js';
21
+ export { getSiteContext, resolveFile, resolveUrl, setSiteContext } from './site.js';
22
+ export { builtinComponents, createRegistry, listComponentNames } from './registry.js';
@@ -0,0 +1,39 @@
1
+ /**
2
+ * SVG icon inlined at build time.
3
+ *
4
+ * The file is read once and its content placed in the page. That is what
5
+ * lets it take its colour from `currentColor` and be styled like everything
6
+ * else — impossible through an `img` tag, which isolates the document.
7
+ *
8
+ * @module @docpensieve/components/logo-icon
9
+ */
10
+ /**
11
+ * Project SVG icon, inlined in the page.
12
+ *
13
+ * @example
14
+ * <LogoIcon src="./icons/book.svg" label="Documentation" />
15
+ *
16
+ * @param {{
17
+ * className?: string, style?: object,
18
+ * src?: string, label?: string, size?: string,
19
+ * }} props `label` describes the icon; without it the icon is treated as
20
+ * decorative and hidden from screen readers — which is right when nearby
21
+ * text already says the same thing. `size` accepts any CSS length.
22
+ * @throws {DocPensieveError} Without `src`, or when the file cannot be read.
23
+ */
24
+ export declare function LogoIcon({ className, style, src, label, size }: {
25
+ className?: string;
26
+ style?: object;
27
+ src?: string;
28
+ label?: string;
29
+ size?: string;
30
+ }): import("react").DetailedReactHTMLElement<{
31
+ className: string | undefined;
32
+ style: object | undefined;
33
+ role: "img" | undefined;
34
+ 'aria-label': string | undefined;
35
+ 'aria-hidden': "true" | undefined;
36
+ dangerouslySetInnerHTML: {
37
+ __html: string;
38
+ };
39
+ }, HTMLElement>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Registry of global components.
3
+ *
4
+ * The components registered here are passed to @mdx-js/mdx as the
5
+ * `components` table: they become usable in any `.mdx` without an import.
6
+ *
7
+ * @module @docpensieve/components/registry
8
+ */
9
+ /**
10
+ * Components shipped with DocPensieve.
11
+ * @type {Record<string, Function>}
12
+ */
13
+ export declare const builtinComponents: Record<string, Function>;
14
+ /**
15
+ * Builds the component table passed to the MDX compiler.
16
+ *
17
+ * @param {Record<string, Function>} [userComponents] Project components, which
18
+ * override the built-in components of the same name.
19
+ * @returns {Record<string, Function>} Table ready for @mdx-js/mdx.
20
+ */
21
+ export declare function createRegistry(userComponents?: Record<string, Function>): Record<string, Function>;
22
+ /**
23
+ * Lists the available component names — useful for a readable error message
24
+ * when an `.mdx` references an unknown component.
25
+ *
26
+ * @param {Record<string, Function>} registry
27
+ * @returns {string[]} Names sorted alphabetically.
28
+ */
29
+ export declare function listComponentNames(registry: Record<string, Function>): string[];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Back to the top of the page.
3
+ *
4
+ * No JavaScript: a link to the `top` fragment, which the HTML specification
5
+ * reserves for the top of the document when no element carries that
6
+ * identifier. The button therefore works without adding anything to the page.
7
+ *
8
+ * It only shows once the page has scrolled, through `animation-timeline`.
9
+ * Where the browser ignores it, it simply stays visible: a button always there
10
+ * is better than a button never there.
11
+ *
12
+ * @module @docpensieve/components/scroll-to-top
13
+ */
14
+ /**
15
+ * Back-to-top button.
16
+ *
17
+ * @param {{
18
+ * className?: string, style?: object, children?: any, label?: string,
19
+ * }} props `label` is read by screen readers. The children replace the arrow
20
+ * with whatever you want.
21
+ */
22
+ export declare function ScrollToTop({ className, style, children, label }: {
23
+ className?: string;
24
+ style?: object;
25
+ children?: any;
26
+ label?: string;
27
+ }): import("react").DetailedReactHTMLElement<{
28
+ className: string | undefined;
29
+ style: object | undefined;
30
+ href: string;
31
+ 'aria-label': string;
32
+ }, HTMLElement>;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Page context handed to components.
3
+ *
4
+ * The compiler plugins rewrite the URLs of the tree built from the Markdown,
5
+ * but that work happens **before** React renders the components: a link
6
+ * produced by a component escapes them. This module gives it what it needs
7
+ * to resolve itself, following the same rules (ADR-006).
8
+ *
9
+ * It also carries what is needed to find a **file** of the version, which a
10
+ * component that includes a resource at build time requires.
11
+ *
12
+ * @module @docpensieve/components/site
13
+ */
14
+ export type SiteContext = {
15
+ /**
16
+ * URL of the page being rendered.
17
+ */
18
+ url: string;
19
+ /**
20
+ * Folder of the source file, mapped into URL
21
+ * space. Base of relative targets: the page URL has one more level.
22
+ */
23
+ dirUrl?: string;
24
+ /**
25
+ * Version root, deployment prefix included.
26
+ */
27
+ basePath: string;
28
+ /**
29
+ * Source file of the page, on disk.
30
+ */
31
+ filepath?: string;
32
+ /**
33
+ * Source folder of the version.
34
+ */
35
+ sourceDir?: string;
36
+ };
37
+ /**
38
+ * Declares the page being rendered.
39
+ *
40
+ * Set by the generator before every page, like the class table.
41
+ *
42
+ * @param {Partial<SiteContext>} [page]
43
+ */
44
+ export declare function setSiteContext(page?: Partial<SiteContext>): void;
45
+ /** @returns {SiteContext} The current context. */
46
+ export declare function getSiteContext(): SiteContext;
47
+ /**
48
+ * Resolves a target written by an author into a site URL.
49
+ *
50
+ * Same rules as for Markdown content: a relative target resolves against the
51
+ * page's folder, an absolute target starts from the version root.
52
+ *
53
+ * @param {string | undefined} target
54
+ * @returns {string | undefined} The resolved target, or as is when external.
55
+ */
56
+ export declare function resolveUrl(target: string | undefined): string | undefined;
57
+ /**
58
+ * Resolves a target into a file path, for a resource read at build time.
59
+ *
60
+ * Same landmarks as for a URL, mapped to the disk: a relative target starts
61
+ * from the page's file, an absolute one from the version folder. Nothing can
62
+ * leave that folder — a page does not read the rest of the machine.
63
+ *
64
+ * @param {string} target
65
+ * @returns {string} Absolute path, inside the source folder.
66
+ * @throws {Error} When the context is missing or the target escapes it.
67
+ */
68
+ export declare function resolveFile(target: string): string;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Level gauge, as a bar or a circle.
3
+ *
4
+ * No JavaScript: the fill is done in CSS, and animates as it enters the
5
+ * viewport where `animation-timeline` exists. Elsewhere, the gauge is simply
6
+ * full — the value stays readable, which is what matters.
7
+ *
8
+ * @module @docpensieve/components/skill
9
+ */
10
+ /** Shapes accepted by the gauge. */
11
+ export declare const SKILL_SHAPES: readonly string[];
12
+ /**
13
+ * Named gauge, from 0 to 100.
14
+ *
15
+ * @example
16
+ * <Skill name="Accessibility" level={80} />
17
+ * <Skill name="Accessibility" level={80} shape="circle" />
18
+ *
19
+ * @param {{
20
+ * className?: string, style?: object, children?: any,
21
+ * name?: any, level?: number, showValue?: boolean, shape?: string,
22
+ * icon?: any, color?: string, label?: string,
23
+ * }} props `children` stands as a comment under the gauge. `showValue` hides
24
+ * the numeric percentage without touching what the gauge announces.
25
+ * `shape` picks between the bar and the circle. `icon` goes before the
26
+ * name — a `LogoIcon` fits there. `color` tints the fill: any CSS colour,
27
+ * the accent colour by default. `label` names the gauge for screen readers
28
+ * when `name` is not text.
29
+ * @throws {DocPensieveError} Without a name, outside 0–100, or with an
30
+ * unknown shape.
31
+ */
32
+ export declare function Skill({ className, style, children, name, level, showValue, shape, icon, color, label, }: {
33
+ className?: string;
34
+ style?: object;
35
+ children?: any;
36
+ name?: any;
37
+ level?: number;
38
+ showValue?: boolean;
39
+ shape?: string;
40
+ icon?: any;
41
+ color?: string;
42
+ label?: string;
43
+ }): import("react").DetailedReactHTMLElement<{
44
+ className: string | undefined;
45
+ style: object | undefined;
46
+ }, HTMLElement>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Stylesheet of the shipped components.
3
+ *
4
+ * @module @docpensieve/components/styles
5
+ */
6
+ /**
7
+ * Reads the default look of the components.
8
+ *
9
+ * It is concatenated with the theme's by the caller: a provider that
10
+ * redefines a slot replaces the `dp-*` class with its own, and these rules
11
+ * then stop applying by themselves.
12
+ *
13
+ * @returns {Promise<string>} CSS, trimmed.
14
+ * @throws {DocPensieveError} When the stylesheet is missing.
15
+ */
16
+ export declare function componentsCss(): Promise<string>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Conditional display by date or duration.
3
+ *
4
+ * **Mind the meaning on a static site**: “right now” means the moment of the
5
+ * **build**, not of reading. A page built in November will still show “the
6
+ * offer starts soon” in January if the site has not been rebuilt in between.
7
+ *
8
+ * This is not a flaw: it is what a time-based component becomes without
9
+ * client-side JavaScript. A scheduled build — a cron job in CI — is enough to
10
+ * keep it right.
11
+ *
12
+ * @module @docpensieve/components/time-timer
13
+ */
14
+ /**
15
+ * Content shown before the period.
16
+ *
17
+ * No wrapper: a `span` around the author's content would become invalid
18
+ * markup as soon as they write a paragraph in it — which happens as soon as a
19
+ * blank line separates their text. The content therefore keeps its nature,
20
+ * inline or block.
21
+ *
22
+ * @param {{ children?: any, start?: string }} props
23
+ */
24
+ export declare function FallbackBefore({ children }: {
25
+ children?: any;
26
+ start?: string;
27
+ }): import("react").FunctionComponentElement<import("react").FragmentProps>;
28
+ /**
29
+ * Content shown after the period.
30
+ *
31
+ * Without a wrapper, for the same reason as {@link FallbackBefore}.
32
+ *
33
+ * @param {{ children?: any, end?: string }} props
34
+ */
35
+ export declare function FallbackAfter({ children }: {
36
+ children?: any;
37
+ end?: string;
38
+ }): import("react").FunctionComponentElement<import("react").FragmentProps>;
39
+ /**
40
+ * Shows its content during a period, with fallbacks before and after.
41
+ *
42
+ * @example
43
+ * <TimeTimer date="25/12/2025">
44
+ * Merry Christmas
45
+ * <FallbackBefore>It is not Christmas yet</FallbackBefore>
46
+ * <FallbackAfter>Christmas is over</FallbackAfter>
47
+ * </TimeTimer>
48
+ *
49
+ * @param {{
50
+ * date?: string, start?: string, duration?: string,
51
+ * strict?: boolean, children?: any, now?: Date,
52
+ * }} props `now` only exists for tests: without it, the build moment stands.
53
+ */
54
+ export declare function TimeTimer({ date, start, duration, strict, children, now }: {
55
+ date?: string;
56
+ start?: string;
57
+ duration?: string;
58
+ strict?: boolean;
59
+ children?: any;
60
+ now?: Date;
61
+ }): any;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tooltip on hover and from the keyboard.
3
+ *
4
+ * No JavaScript: the bubble is a real element that CSS reveals on hover and
5
+ * on focus. The trigger is therefore reachable from the keyboard, and the
6
+ * bubble announced through `aria-describedby` rather than guessed.
7
+ *
8
+ * @module @docpensieve/components/tooltip
9
+ */
10
+ /** Sides the bubble can sit on. */
11
+ export declare const TOOLTIP_PLACEMENTS: readonly string[];
12
+ /**
13
+ * Term with a tooltip.
14
+ *
15
+ * @example
16
+ * <Tooltip text="Generation of a complete site">build</Tooltip>
17
+ *
18
+ * @param {{
19
+ * className?: string, style?: object, children?: any,
20
+ * text?: string, placement?: string,
21
+ * }} props `text` is the content of the bubble; the children are the term it
22
+ * explains.
23
+ * @throws {DocPensieveError} Without text, or with an unknown side.
24
+ */
25
+ export declare function Tooltip({ className, style, children, text, placement }: {
26
+ className?: string;
27
+ style?: object;
28
+ children?: any;
29
+ text?: string;
30
+ placement?: string;
31
+ }): import("react").DetailedReactHTMLElement<{
32
+ className: string | undefined;
33
+ style: object | undefined;
34
+ }, HTMLElement>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Collapsible tree.
3
+ *
4
+ * No JavaScript: expanding is the native behaviour of `<details>`, which
5
+ * works from the keyboard and stays printable.
6
+ *
7
+ * The structure is a nested list, not a `role="tree"`. That role promises a
8
+ * screen reader arrow-key navigation that nothing here would implement:
9
+ * announcing it would lie about what the page can do.
10
+ *
11
+ * @module @docpensieve/components/tree
12
+ */
13
+ /**
14
+ * Root of a tree.
15
+ *
16
+ * @param {{ className?: string, style?: object, children?: any }} props
17
+ */
18
+ export declare function Tree({ className, style, children }: {
19
+ className?: string;
20
+ style?: object;
21
+ children?: any;
22
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<boolean>>;
23
+ /**
24
+ * Entry of a tree.
25
+ *
26
+ * With children, it is a collapsible branch; without, a leaf. The difference
27
+ * is read from the writing, with no prop to set.
28
+ *
29
+ * @param {{
30
+ * className?: string, style?: object, children?: any,
31
+ * label?: any, open?: boolean,
32
+ * }} props `open` expands the branch as soon as the page opens.
33
+ * @throws {DocPensieveError} Outside a `Tree`, or without a label.
34
+ */
35
+ export declare function TreeItem({ className, style, children, label, open }: {
36
+ className?: string;
37
+ style?: object;
38
+ children?: any;
39
+ label?: any;
40
+ open?: boolean;
41
+ }): import("react").DetailedReactHTMLElement<{
42
+ className: string | undefined;
43
+ style: object | undefined;
44
+ }, HTMLElement>;