dowel-ui 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ A dowel is the hidden peg that joins two boards so the seam does not show. That
11
11
  **[Documentation](https://lacodda.github.io/dowel/)** — what everything is and why it is that way.
12
12
  **[The stand](https://lacodda.github.io/dowel/stand/)** — every component, live, in either theme and in the accent of any product of the line.
13
13
 
14
- **Status:** v0.24.0 - the theme, the scales, an accent per product, seventy components - overlays, menus, the command palette, the table, a hundred thousand rows, the screens between asking for data and showing it, the three ways of saying something happened, and now charts: a figure and its movement, the shape of a history, a bar of stretches, a year of days, columns over a baseline and a level between the readings - and the gates each one passes: axe, the keyboard, a dependency budget and a picture in both themes. Every component has a page of its own on the stand, which remembers the theme and the accent you left it in. Components install from a versioned registry, the docs are served in the form an agent reads, and `dowel check` tells a project what stands between it and the vocabulary. Two products of the line live on it. See the [roadmap](#roadmap).
14
+ **Status:** v0.25.0 - the theme, the scales, an accent per product, seventy-six components - overlays, menus, the command palette, the table, a hundred thousand rows, the screens between asking for data and showing it, the three ways of saying something happened, charts, and now text and code: rendered markdown through one stylesheet, a code block whose highlighter is yours, a comparison whose two columns stay in step, and a JSON document read rather than parsed by eye - and the gates each one passes: axe, the keyboard, a dependency budget and a picture in both themes. Every component has a page of its own on the stand, which remembers the theme and the accent you left it in. Components install from a versioned registry, the docs are served in the form an agent reads, and `dowel check` tells a project what stands between it and the vocabulary. Two products of the line live on it. See the [roadmap](#roadmap).
15
15
 
16
16
  ## The theme
17
17
 
@@ -68,10 +68,21 @@ A product of the line states one thing about its appearance - which product it i
68
68
  @import 'dowel-ui/accents/kilna.css';
69
69
  ```
70
70
 
71
+ Text a product does not write by hand - rendered markdown, a description from a CMS, a model's reply - is the one thing a component cannot style, because the tags arrive already made. That is a second stylesheet, imported the same way and applied with one class:
72
+
73
+ ```css
74
+ @import 'dowel-ui/prose.css';
75
+ ```
76
+
77
+ ```tsx
78
+ <div className="prose" dangerouslySetInnerHTML={{ __html: sanitised }} />
79
+ ```
80
+
71
81
  Or copy the files in instead of depending on the package:
72
82
 
73
83
  ```bash
74
84
  npx shadcn@latest add https://lacodda.github.io/dowel/r/theme.json
85
+ npx shadcn@latest add https://lacodda.github.io/dowel/r/prose.json
75
86
  ```
76
87
 
77
88
  ## Primitives
@@ -93,12 +104,12 @@ npx shadcn@latest add https://lacodda.github.io/dowel/r/app.json
93
104
  A set carries no files of its own: it resolves into the same per-component
94
105
  installs you could have typed, so nothing of it survives in your project and
95
106
  there is no membership to leave. Each minor of the registry is also served
96
- frozen at `r/v0.14/…`, for an install that has to be repeatable - inside a
107
+ frozen at `r/v0.25/…`, for an install that has to be repeatable - inside a
97
108
  snapshot the cross-references point into the same snapshot, so a component and
98
109
  the sibling it reuses are the pair that shipped together. See
99
110
  [installing from the registry](https://lacodda.github.io/dowel/guides/registry/).
100
111
 
101
- Seventy of them so far. The everyday ones - Button, Input, Textarea, Panel,
112
+ Seventy-six of them so far. The everyday ones - Button, Input, Textarea, Panel,
102
113
  Badge, Chip, Kbd, Spinner, Truncate and Copyable; Field and the three controls
103
114
  that answer a question - Checkbox, RadioGroup and Switch; five for a number or
104
115
  a judgement - NumberField, Slider, RatingScale, DurationField and
@@ -118,7 +129,10 @@ into stretches; ActivityHeatmap with its legend and its `activity-weeks`, for a
118
129
  year of days; BarChart for a period at a time, LineChart with its `line-scale` for a level
119
130
  between the readings; and five for the screens
120
131
  between asking for data and showing it: Skeleton, EmptyState, Progress,
121
- QueryState and ErrorBoundary.
132
+ QueryState and ErrorBoundary. And six for text and code: the `prose`
133
+ stylesheet for markdown a product did not write by hand, CodeBlock with
134
+ CopyButton beside it, DiffView with the `diff-lines` that keeps its two
135
+ columns in step, and JsonViewer over its `json-rows`.
122
136
 
123
137
  Those last three are the ones products keep confusing, so each page names all
124
138
  four options: a **toast** goes away, an **alert** is still true after a reload,
package/dist/index.d.ts CHANGED
@@ -22,6 +22,15 @@ export declare const chartTokens: readonly ["chart-grid", "chart-axis"];
22
22
  * `scaleTokens`. The faintest step stays distinct from an empty cell, or the
23
23
  * grid claims a day was worked at zero when nobody reported it. */
24
24
  export declare const heatTokens: readonly ["heat-1", "heat-2", "heat-3", "heat-4", "heat-5"];
25
+ /** Syntax: the eight kinds of thing in a piece of code that are worth telling
26
+ * apart in every language. Fixed like the series - `if` should not be magenta
27
+ * in one product and cobalt in another - but measured against a different
28
+ * threshold: these are read as text, so every slot clears 4.5:1 against the
29
+ * surface code sits on, where a series colour only has to clear 3:1 as a
30
+ * filled mark. They are also the one palette here not held to the
31
+ * colour-blind floor, because syntax colour restates what the text already
32
+ * says and CodeBlock's default draws none of it. */
33
+ export declare const syntaxTokens: readonly ["syntax-keyword", "syntax-string", "syntax-number", "syntax-comment", "syntax-name", "syntax-type", "syntax-punctuation", "syntax-meta"];
25
34
  /** Tokens a product overrides to make the theme its own: the accent from the
26
35
  * brand-line registry, and how much of it bleeds into the greys. */
27
36
  export declare const themeParameters: readonly ["accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink"];
@@ -46,7 +55,7 @@ export declare const layerTokens: readonly ["z-popup", "z-sticky", "z-menu", "z-
46
55
  * vocabulary - a docs page, an inspector, the JSON export, the test that keeps
47
56
  * this file honest against the stylesheet - reads this, so a new category
48
57
  * cannot be added and quietly missed by half of them. */
49
- export declare const allTokens: readonly ["bg", "raise", "soft", "softer", "line", "line-2", "text", "dim", "faint", "accent", "accent-2", "accent-soft", "on-accent", "on-good", "on-warn", "on-bad", "on-info", "good", "good-soft", "warn", "warn-soft", "bad", "bad-soft", "info", "info-soft", "series-1", "series-2", "series-3", "series-4", "series-5", "series-6", "series-7", "series-8", "scale-100", "scale-200", "scale-300", "scale-400", "scale-500", "scale-600", "scale-700", "chart-grid", "chart-axis", "heat-1", "heat-2", "heat-3", "heat-4", "heat-5", "accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink", "shadow-lift", "shadow-raise", "shadow-float", "radius-xs", "radius-sm", "radius-md", "radius-lg", "radius-xl", "radius-2xl", "radius-inner", "font-sans", "font-mono", "text-2xs", "text-xs", "text-sm", "text-base", "text-lg", "text-xl", "text-2xl", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "tracking-caption", "tracking-tight", "duration-quick", "duration-base", "duration-slow", "ease-out", "ease-in-out", "z-popup", "z-sticky", "z-menu", "z-floating", "z-overlay", "z-modal", "z-palette", "z-toast"];
58
+ export declare const allTokens: readonly ["bg", "raise", "soft", "softer", "line", "line-2", "text", "dim", "faint", "accent", "accent-2", "accent-soft", "on-accent", "on-good", "on-warn", "on-bad", "on-info", "good", "good-soft", "warn", "warn-soft", "bad", "bad-soft", "info", "info-soft", "series-1", "series-2", "series-3", "series-4", "series-5", "series-6", "series-7", "series-8", "scale-100", "scale-200", "scale-300", "scale-400", "scale-500", "scale-600", "scale-700", "chart-grid", "chart-axis", "heat-1", "heat-2", "heat-3", "heat-4", "heat-5", "syntax-keyword", "syntax-string", "syntax-number", "syntax-comment", "syntax-name", "syntax-type", "syntax-punctuation", "syntax-meta", "accent-base", "neutral-base", "neutral-tint", "neutral-tint-strong", "ground", "ink", "shadow-lift", "shadow-raise", "shadow-float", "radius-xs", "radius-sm", "radius-md", "radius-lg", "radius-xl", "radius-2xl", "radius-inner", "font-sans", "font-mono", "text-2xs", "text-xs", "text-sm", "text-base", "text-lg", "text-xl", "text-2xl", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "tracking-caption", "tracking-tight", "duration-quick", "duration-base", "duration-slow", "ease-out", "ease-in-out", "z-popup", "z-sticky", "z-menu", "z-floating", "z-overlay", "z-modal", "z-palette", "z-toast"];
50
59
  export type ColorToken = (typeof colorTokens)[number];
51
60
  export type ThemeParameter = (typeof themeParameters)[number];
52
61
  export type ElevationToken = (typeof elevationTokens)[number];
@@ -54,7 +63,12 @@ export type RadiusToken = (typeof radiusTokens)[number];
54
63
  export type TypeToken = (typeof typeTokens)[number];
55
64
  export type MotionToken = (typeof motionTokens)[number];
56
65
  export type LayerToken = (typeof layerTokens)[number];
57
- export type Token = ColorToken | ThemeParameter | ElevationToken | RadiusToken | TypeToken | MotionToken | LayerToken;
66
+ export type SeriesToken = (typeof seriesTokens)[number];
67
+ export type ScaleToken = (typeof scaleTokens)[number];
68
+ export type ChartToken = (typeof chartTokens)[number];
69
+ export type HeatToken = (typeof heatTokens)[number];
70
+ export type SyntaxToken = (typeof syntaxTokens)[number];
71
+ export type Token = ColorToken | SeriesToken | ScaleToken | ChartToken | HeatToken | SyntaxToken | ThemeParameter | ElevationToken | RadiusToken | TypeToken | MotionToken | LayerToken;
58
72
  /** The custom property a token is read from: `token('accent')` is
59
73
  * `'--accent'`. Spelled out here so that no caller builds the string itself
60
74
  * and gets the prefix subtly wrong. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,QAAQ,EACR,cAAc,EACd,KAAK,KAAK,GACX,MAAM,YAAY,CAAA;AAEnB;6DAC6D;AAC7D,eAAO,MAAM,WAAW,qQA0Bd,CAAA;AAEV;;;;4EAI4E;AAC5E,eAAO,MAAM,YAAY,2GASf,CAAA;AAEV;kDACkD;AAClD,eAAO,MAAM,WAAW,sGAQd,CAAA;AAEV;4CAC4C;AAC5C,eAAO,MAAM,WAAW,uCAAwC,CAAA;AAEhE;;;;mEAImE;AACnE,eAAO,MAAM,UAAU,6DAA8D,CAAA;AAErF;oEACoE;AACpE,eAAO,MAAM,eAAe,kGAOlB,CAAA;AAEV;yDACyD;AACzD,eAAO,MAAM,eAAe,0DAA2D,CAAA;AAEvF;8DAC8D;AAC9D,eAAO,MAAM,YAAY,0GAQf,CAAA;AAEV;iCACiC;AACjC,eAAO,MAAM,UAAU,gOAeb,CAAA;AAEV;;0CAE0C;AAC1C,eAAO,MAAM,YAAY,0FAMf,CAAA;AAEV;;qEAEqE;AACrE,eAAO,MAAM,WAAW,0GASd,CAAA;AAEV;;;yDAGyD;AACzD,eAAO,MAAM,SAAS,snCAYZ,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AACnD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,KAAK,GACb,UAAU,GACV,cAAc,GACd,cAAc,GACd,WAAW,GACX,SAAS,GACT,WAAW,GACX,UAAU,CAAA;AAEd;;uCAEuC;AACvC,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAEzC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,QAAQ,EACR,cAAc,EACd,KAAK,KAAK,GACX,MAAM,YAAY,CAAA;AAEnB;6DAC6D;AAC7D,eAAO,MAAM,WAAW,qQA0Bd,CAAA;AAEV;;;;4EAI4E;AAC5E,eAAO,MAAM,YAAY,2GASf,CAAA;AAEV;kDACkD;AAClD,eAAO,MAAM,WAAW,sGAQd,CAAA;AAEV;4CAC4C;AAC5C,eAAO,MAAM,WAAW,uCAAwC,CAAA;AAEhE;;;;mEAImE;AACnE,eAAO,MAAM,UAAU,6DAA8D,CAAA;AAErF;;;;;;;oDAOoD;AACpD,eAAO,MAAM,YAAY,oJASf,CAAA;AAEV;oEACoE;AACpE,eAAO,MAAM,eAAe,kGAOlB,CAAA;AAEV;yDACyD;AACzD,eAAO,MAAM,eAAe,0DAA2D,CAAA;AAEvF;8DAC8D;AAC9D,eAAO,MAAM,YAAY,0GAQf,CAAA;AAEV;iCACiC;AACjC,eAAO,MAAM,UAAU,gOAeb,CAAA;AAEV;;0CAE0C;AAC1C,eAAO,MAAM,YAAY,0FAMf,CAAA;AAEV;;qEAEqE;AACrE,eAAO,MAAM,WAAW,0GASd,CAAA;AAEV;;;yDAGyD;AACzD,eAAO,MAAM,SAAS,+vCAaZ,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAC7D,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AACnD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAKrD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AACnD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvD,MAAM,MAAM,KAAK,GACb,UAAU,GACV,WAAW,GACX,UAAU,GACV,UAAU,GACV,SAAS,GACT,WAAW,GACX,cAAc,GACd,cAAc,GACd,WAAW,GACX,SAAS,GACT,WAAW,GACX,UAAU,CAAA;AAEd;;uCAEuC;AACvC,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAEzC"}
package/dist/index.js CHANGED
@@ -81,6 +81,24 @@ export const chartTokens = ['chart-grid', 'chart-axis'];
81
81
  * `scaleTokens`. The faintest step stays distinct from an empty cell, or the
82
82
  * grid claims a day was worked at zero when nobody reported it. */
83
83
  export const heatTokens = ['heat-1', 'heat-2', 'heat-3', 'heat-4', 'heat-5'];
84
+ /** Syntax: the eight kinds of thing in a piece of code that are worth telling
85
+ * apart in every language. Fixed like the series - `if` should not be magenta
86
+ * in one product and cobalt in another - but measured against a different
87
+ * threshold: these are read as text, so every slot clears 4.5:1 against the
88
+ * surface code sits on, where a series colour only has to clear 3:1 as a
89
+ * filled mark. They are also the one palette here not held to the
90
+ * colour-blind floor, because syntax colour restates what the text already
91
+ * says and CodeBlock's default draws none of it. */
92
+ export const syntaxTokens = [
93
+ 'syntax-keyword',
94
+ 'syntax-string',
95
+ 'syntax-number',
96
+ 'syntax-comment',
97
+ 'syntax-name',
98
+ 'syntax-type',
99
+ 'syntax-punctuation',
100
+ 'syntax-meta',
101
+ ];
84
102
  /** Tokens a product overrides to make the theme its own: the accent from the
85
103
  * brand-line registry, and how much of it bleeds into the greys. */
86
104
  export const themeParameters = [
@@ -156,6 +174,7 @@ export const allTokens = [
156
174
  ...scaleTokens,
157
175
  ...chartTokens,
158
176
  ...heatTokens,
177
+ ...syntaxTokens,
159
178
  ...themeParameters,
160
179
  ...elevationTokens,
161
180
  ...radiusTokens,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAoB,MAAM,WAAW,CAAA;AACvE,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,QAAQ,EACR,cAAc,GAEf,MAAM,YAAY,CAAA;AAEnB;6DAC6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI;IACJ,OAAO;IACP,MAAM;IACN,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,UAAU;IACV,aAAa;IACb,WAAW;IACX,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,MAAM;IACN,WAAW;IACX,MAAM;IACN,WAAW;IACX,KAAK;IACL,UAAU;IACV,MAAM;IACN,WAAW;CACH,CAAA;AAEV;;;;4EAI4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;CACF,CAAA;AAEV;kDACkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;CACH,CAAA;AAEV;4CAC4C;AAC5C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,YAAY,CAAU,CAAA;AAEhE;;;;mEAImE;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAErF;oEACoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa;IACb,cAAc;IACd,cAAc;IACd,qBAAqB;IACrB,QAAQ;IACR,KAAK;CACG,CAAA;AAEV;yDACyD;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,cAAc,CAAU,CAAA;AAEvF;8DAC8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,cAAc;CACN,CAAA;AAEV;iCACiC;AACjC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,WAAW;IACX,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,WAAW;IACX,SAAS;IACT,SAAS;IACT,UAAU;IACV,oBAAoB;IACpB,oBAAoB;IACpB,sBAAsB;IACtB,kBAAkB;IAClB,gBAAgB;CACR,CAAA;AAEV;;0CAE0C;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,UAAU;IACV,aAAa;CACL,CAAA;AAEV;;qEAEqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS;IACT,UAAU;IACV,QAAQ;IACR,YAAY;IACZ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS;CACD,CAAA;AAEV;;;yDAGyD;AACzD,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,GAAG,WAAW;IACd,GAAG,YAAY;IACf,GAAG,WAAW;IACd,GAAG,WAAW;IACd,GAAG,UAAU;IACb,GAAG,eAAe;IAClB,GAAG,eAAe;IAClB,GAAG,YAAY;IACf,GAAG,UAAU;IACb,GAAG,YAAY;IACf,GAAG,WAAW;CACN,CAAA;AAkBV;;uCAEuC;AACvC,MAAM,UAAU,KAAK,CAAC,IAAW;IAC/B,OAAO,KAAK,IAAI,EAAE,CAAA;AACpB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/prose.css ADDED
@@ -0,0 +1,448 @@
1
+ /*
2
+ * dowel prose - the shape of text a product did not write by hand.
3
+ *
4
+ * Every other rule in this system is applied by a component, because a
5
+ * component owns the element it draws. Rendered markdown is the case where
6
+ * that is impossible: the product hands the DOM a string of HTML - from
7
+ * `marked`, from a CMS, from a model's reply - and there is no React element
8
+ * to hang a class on. The tags arrive already made. Only a descendant selector
9
+ * reaches them.
10
+ *
11
+ * kilna proved the shape before this file existed, as thirty `[&_h1]:mt-4`
12
+ * arbitrary variants inside one `className` string. It works and it is a
13
+ * paragraph of unreadable text that no second product can share, which is the
14
+ * whole argument for moving it here.
15
+ *
16
+ * Scoped to `.prose`, so nothing leaks: a stylesheet that styled `h2`
17
+ * globally would reach into every component that happens to render one.
18
+ *
19
+ * WHY NOT A TYPOGRAPHY PLUGIN. `@tailwindcss/typography` answers the same
20
+ * question and brings its own answer to a different one - its own type scale,
21
+ * its own greys, its own idea of measure. Installing it next to this theme
22
+ * means two vocabularies describing the same text, and the one that wins is
23
+ * whichever loaded last. Every value below is a token from `theme.css`; there
24
+ * is not a single colour or size written down here.
25
+ *
26
+ * WHAT THIS IS NOT FOR. Interface text - a label, a row, a button - is styled
27
+ * by the component that draws it. `.prose` is for a reading column: a note, a
28
+ * description, an article, a chat reply. Wrapping a form in it is how a screen
29
+ * ends up with two competing ideas of what `text-sm` means.
30
+ *
31
+ * Import after the theme:
32
+ *
33
+ * @import 'tailwindcss';
34
+ * @import './dowel/theme.css';
35
+ * @import './dowel/prose.css';
36
+ */
37
+
38
+ .prose {
39
+ /*
40
+ * The reading size is `--text-base`, not the `--text-sm` the interface runs
41
+ * at, and the two are different on purpose. Chrome is scanned - a label is
42
+ * recognised rather than read - and it packs tighter the less of it there
43
+ * is. Prose is read word by word, and 12px of continuous text is where a
44
+ * reader starts leaning in. The products already knew this and did it by
45
+ * hand: kilna's rendered markdown sets `text-sm` (12px) against an interface
46
+ * of 11px, the same one-step lift.
47
+ */
48
+ font-size: var(--text-base);
49
+
50
+ /*
51
+ * Line height is set here rather than inherited from the size token, which
52
+ * carries 20px for 14px text - right for a label, tight for a paragraph.
53
+ * 1.65 is the ratio the eye returns to the start of the next line with; it
54
+ * is a ratio rather than a length so a product that scales the size up for a
55
+ * reading view keeps the proportion.
56
+ */
57
+ line-height: 1.65;
58
+ color: var(--text);
59
+
60
+ /*
61
+ * A measure, not a width. Prose is unreadable across a wide window - the eye
62
+ * loses the line it is returning from - and `ch` is the unit that says so in
63
+ * the terms the limit is actually about: characters, at whatever size the
64
+ * text is drawn. 68 is inside the 45-75 the typographic literature agrees
65
+ * on, at the wide end because these are technical texts with code and long
66
+ * identifiers in them.
67
+ *
68
+ * A product that has its own column - a chat bubble, a card - overrides
69
+ * `max-width` and loses nothing else.
70
+ */
71
+ max-width: 68ch;
72
+
73
+ /*
74
+ * The shell of a desktop app usually turns selection off, so that dragging
75
+ * inside a window moves the window. Text someone came to READ has to hand it
76
+ * back, or the one thing a reader wants to do with a paragraph - take a
77
+ * sentence out of it - is the thing the app forbids.
78
+ */
79
+ user-select: text;
80
+ -webkit-user-select: text;
81
+ }
82
+
83
+ /*
84
+ * Vertical rhythm.
85
+ *
86
+ * Margins collapse between siblings, so stating both a top and a bottom on
87
+ * every block would double the gap at some joins and not others depending on
88
+ * which value was larger. Instead: one bottom margin on everything, and the
89
+ * top margin belongs to the headings alone, which are the only elements that
90
+ * need more space above them than below - a heading belongs to what follows
91
+ * it, and sitting equidistant between two paragraphs it appears to belong to
92
+ * neither.
93
+ */
94
+ .prose > * {
95
+ margin-block: 0 0.75em;
96
+ }
97
+
98
+ /* The first and last child never push the container open: a rendered note
99
+ * inside a bordered card would otherwise have a gap at the top that the card's
100
+ * own padding did not put there. */
101
+ .prose > :first-child {
102
+ margin-block-start: 0;
103
+ }
104
+ .prose > :last-child {
105
+ margin-block-end: 0;
106
+ }
107
+
108
+ /*
109
+ * Headings.
110
+ *
111
+ * The scale is the theme's, stepped down from a document's h1 - and it starts
112
+ * lower than a web page's would, because prose here is almost always a section
113
+ * INSIDE a screen that already has a title. An h1 drawn at 21px next to a page
114
+ * heading of 18px makes the note look like the more important thing on screen.
115
+ *
116
+ * `text-wrap: balance` on headings only: it is expensive on long text and
117
+ * makes a two-line heading break in the middle rather than leaving one word
118
+ * alone on the second line.
119
+ */
120
+ .prose :is(h1, h2, h3, h4, h5, h6) {
121
+ margin-block: 1.6em 0.5em;
122
+ font-weight: var(--font-weight-semibold);
123
+ line-height: 1.3;
124
+ text-wrap: balance;
125
+ /* A heading that ends up at the top of a scrolled container should not be
126
+ * flush against its edge. */
127
+ scroll-margin-block-start: 1rem;
128
+ }
129
+
130
+ .prose h1 {
131
+ font-size: var(--text-xl);
132
+ letter-spacing: var(--tracking-tight);
133
+ }
134
+ .prose h2 {
135
+ font-size: var(--text-lg);
136
+ letter-spacing: var(--tracking-tight);
137
+ }
138
+ .prose h3 {
139
+ font-size: var(--text-base);
140
+ }
141
+
142
+ /*
143
+ * h4 and below stop growing and start differentiating by other means: a
144
+ * document nested six levels deep has run out of sizes long before it runs out
145
+ * of levels, and inventing two more steps inside four pixels is the noise the
146
+ * type scale exists to remove. They are the body size, set apart by weight and
147
+ * by colour.
148
+ */
149
+ .prose :is(h4, h5, h6) {
150
+ font-size: var(--text-base);
151
+ color: var(--dim);
152
+ }
153
+
154
+ /* A heading directly after another has nothing between them to separate. */
155
+ .prose :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) {
156
+ margin-block-start: 0.8em;
157
+ }
158
+
159
+ /*
160
+ * Lists.
161
+ *
162
+ * Tailwind's preflight strips the markers, which is right for the interface -
163
+ * a menu is a `ul` and must not have bullets - and wrong here, where a list is
164
+ * a list. They are put back, and `outside` so the marker hangs in the indent
165
+ * and the text of a wrapped item lines up with itself rather than with the
166
+ * bullet.
167
+ */
168
+ .prose :is(ul, ol) {
169
+ padding-inline-start: 1.5em;
170
+ }
171
+ .prose ul {
172
+ list-style: disc;
173
+ }
174
+ .prose ol {
175
+ list-style: decimal;
176
+ }
177
+ /*
178
+ * `--dim`, not `--faint`, and that was measured rather than chosen.
179
+ *
180
+ * A bullet looks like furniture, so the faintest token is the instinct. But
181
+ * the marker is what says "this is a list" - drop it and an ordered list loses
182
+ * its numbers, which are content. On the stand it came out at 3.17:1 against
183
+ * the surface, below the 4.5:1 that anything carrying meaning has to clear,
184
+ * and it read as a smudge at the size a bullet actually is. `--dim` puts it at
185
+ * 6.2:1 and still sits back from the text.
186
+ */
187
+ .prose li::marker {
188
+ color: var(--dim);
189
+ }
190
+ .prose li {
191
+ margin-block: 0.25em;
192
+ }
193
+
194
+ /* A nested list belongs to the item above it, not to the gap after it. */
195
+ .prose li > :is(ul, ol) {
196
+ margin-block: 0.25em;
197
+ }
198
+
199
+ /* A task list from markdown: the checkbox replaces the marker, so the bullet
200
+ * beside it would be a second one saying the same thing. */
201
+ .prose li:has(> input[type='checkbox']:first-child) {
202
+ list-style: none;
203
+ margin-inline-start: -1.25em;
204
+ }
205
+ .prose li > input[type='checkbox'] {
206
+ margin-inline-end: 0.4em;
207
+ accent-color: var(--accent);
208
+ }
209
+
210
+ /*
211
+ * Inline code.
212
+ *
213
+ * `0.9em` rather than a token: a monospaced face at the same nominal size as
214
+ * the text around it looks larger, because its lowercase letters are taller
215
+ * relative to the em. The correction is proportional to whatever size the
216
+ * surrounding text happens to be, which a fixed token could not follow.
217
+ */
218
+ .prose code {
219
+ font-family: var(--font-mono);
220
+ font-size: 0.9em;
221
+ background-color: var(--soft);
222
+ border-radius: var(--radius-xs);
223
+ padding: 0.15em 0.35em;
224
+ /* A long identifier in the middle of a sentence must be allowed to break,
225
+ * or it pushes the whole column wider than its measure. */
226
+ overflow-wrap: anywhere;
227
+ }
228
+
229
+ /*
230
+ * A code block is not a big inline code. The padding, background and radius
231
+ * belong to the `pre`; the `code` inside it gives them all up, or the block
232
+ * gets a second inset panel drawn inside itself - which is exactly what
233
+ * happens when a typography plugin's inline rule is left to apply here.
234
+ *
235
+ * `overflow-x: auto` rather than wrapping: a wrapped line of code is a line
236
+ * that lies about where it ends, and indentation is how code is read.
237
+ */
238
+ .prose pre {
239
+ font-family: var(--font-mono);
240
+ font-size: var(--text-sm);
241
+ line-height: 1.55;
242
+ background-color: var(--soft);
243
+ border: 1px solid var(--line);
244
+ border-radius: var(--radius-md);
245
+ padding: 0.75rem 0.85rem;
246
+ overflow-x: auto;
247
+ /* `tab-size: 2` is the line's own indent; the browser default of 8 turns a
248
+ * tab-indented file into a horizontal scroll for nothing. */
249
+ tab-size: 2;
250
+ }
251
+
252
+ .prose pre code {
253
+ background-color: transparent;
254
+ border-radius: 0;
255
+ padding: 0;
256
+ font-size: inherit;
257
+ /* Inside a scrolling block, breaking a long line would defeat the scroll. */
258
+ overflow-wrap: normal;
259
+ }
260
+
261
+ /*
262
+ * Links.
263
+ *
264
+ * `--accent-2` rather than `--accent`: on the dark theme the accent is the
265
+ * product's own colour at full strength, which against body text reads as a
266
+ * button that failed to draw. The partner shade is the one the products use
267
+ * for a link, and it is also the one with room to darken on hover.
268
+ *
269
+ * Underlined, always. Colour alone is not a link - a reader who does not see
270
+ * the hue gets no signal at all - and this is the one place in the system
271
+ * where the rule "meaning never rests on colour" has a standard answer.
272
+ */
273
+ .prose a {
274
+ color: var(--accent-2);
275
+ text-decoration: underline;
276
+ /* The underline drops below the descenders instead of striking through
277
+ * them, which is the difference between a link and a crossed-out word. */
278
+ text-underline-offset: 0.2em;
279
+ text-decoration-thickness: from-font;
280
+ overflow-wrap: anywhere;
281
+ }
282
+
283
+ .prose a:hover {
284
+ color: var(--accent);
285
+ }
286
+
287
+ /*
288
+ * A quotation.
289
+ *
290
+ * A rule on the left and dimmed text, rather than italics: a blockquote is
291
+ * frequently a paragraph or more, and a long passage in italic is slower to
292
+ * read for everyone and materially harder for some dyslexic readers.
293
+ */
294
+ .prose blockquote {
295
+ border-inline-start: 2px solid var(--line-2);
296
+ padding-inline-start: 0.9em;
297
+ color: var(--dim);
298
+ }
299
+
300
+ /*
301
+ * A table inside prose.
302
+ *
303
+ * `display: block` with its own scroll, because the one thing a table must not
304
+ * do in a reading column is set the column's width: a note with a six-column
305
+ * table in it would push every paragraph around it out to the table's width.
306
+ * The cost is stated - a block-level table no longer participates in the
307
+ * column's own layout - and it is the right trade for text.
308
+ */
309
+ .prose table {
310
+ display: block;
311
+ max-width: 100%;
312
+ overflow-x: auto;
313
+ border-collapse: collapse;
314
+ font-size: var(--text-sm);
315
+ }
316
+
317
+ .prose :is(th, td) {
318
+ border: 1px solid var(--line);
319
+ padding: 0.3em 0.55em;
320
+ text-align: start;
321
+ vertical-align: top;
322
+ }
323
+
324
+ .prose th {
325
+ background-color: var(--soft);
326
+ font-weight: var(--font-weight-semibold);
327
+ }
328
+
329
+ /*
330
+ * A horizontal rule is a section break, so the space around it is the point;
331
+ * a hairline with a paragraph's gap either side reads as a mistake.
332
+ */
333
+ .prose hr {
334
+ border: 0;
335
+ border-block-start: 1px solid var(--line);
336
+ margin-block: 2em;
337
+ }
338
+
339
+ .prose :is(strong, b) {
340
+ font-weight: var(--font-weight-semibold);
341
+ color: var(--text);
342
+ }
343
+
344
+ .prose :is(em, i) {
345
+ font-style: italic;
346
+ }
347
+
348
+ .prose :is(s, del) {
349
+ color: var(--dim);
350
+ }
351
+
352
+ .prose mark {
353
+ background-color: var(--accent-soft);
354
+ color: inherit;
355
+ border-radius: var(--radius-xs);
356
+ padding: 0.05em 0.2em;
357
+ }
358
+
359
+ /*
360
+ * An image in prose is never wider than the column, and keeps its ratio when
361
+ * it is constrained. `display: block` because an inline image sits on the text
362
+ * baseline and leaves a strip of descender space under it that looks like a
363
+ * broken margin.
364
+ */
365
+ .prose img {
366
+ display: block;
367
+ max-width: 100%;
368
+ height: auto;
369
+ border-radius: var(--radius-sm);
370
+ }
371
+
372
+ /*
373
+ * `kbd` is drawn as a key rather than as code: a reader who sees `Ctrl` in the
374
+ * same grey box as a variable name has to work out which it is. This matches
375
+ * the Kbd primitive, so a key looks the same whether a component drew it or
376
+ * markdown did.
377
+ */
378
+ .prose kbd {
379
+ font-family: var(--font-mono);
380
+ font-size: 0.85em;
381
+ background-color: var(--raise);
382
+ border: 1px solid var(--line-2);
383
+ border-block-end-width: 2px;
384
+ border-radius: var(--radius-xs);
385
+ padding: 0.1em 0.35em;
386
+ color: var(--dim);
387
+ }
388
+
389
+ /*
390
+ * A definition list, which markdown does not produce but a CMS does.
391
+ */
392
+ .prose dt {
393
+ font-weight: var(--font-weight-semibold);
394
+ margin-block-start: 0.75em;
395
+ }
396
+ .prose dd {
397
+ margin-inline-start: 1.5em;
398
+ color: var(--dim);
399
+ }
400
+
401
+ /*
402
+ * A footnote reference and the notes at the bottom - what `remark-gfm`
403
+ * produces. Smaller and dimmer, because a footnote that reads at the weight of
404
+ * the text interrupts the sentence carrying it.
405
+ */
406
+ .prose sup a {
407
+ text-decoration: none;
408
+ font-size: 0.8em;
409
+ }
410
+ .prose .footnotes {
411
+ font-size: var(--text-sm);
412
+ color: var(--dim);
413
+ border-block-start: 1px solid var(--line);
414
+ margin-block-start: 2em;
415
+ padding-block-start: 0.75em;
416
+ }
417
+
418
+ /*
419
+ * Tight: the same prose in a place that has no room for a reading column - a
420
+ * chat bubble, a table cell, a hover card. The rhythm compresses and the
421
+ * measure is given up to the container, because in a bubble the container IS
422
+ * the measure. Nothing else changes: the same tags, the same tokens.
423
+ */
424
+ .prose-tight {
425
+ font-size: var(--text-sm);
426
+ line-height: 1.55;
427
+ max-width: none;
428
+ }
429
+
430
+ .prose-tight > * {
431
+ margin-block: 0 0.5em;
432
+ }
433
+
434
+ .prose-tight :is(h1, h2, h3, h4, h5, h6) {
435
+ margin-block: 1em 0.35em;
436
+ }
437
+
438
+ .prose-tight :is(h1, h2) {
439
+ font-size: var(--text-base);
440
+ }
441
+
442
+ .prose-tight h3 {
443
+ font-size: var(--text-sm);
444
+ }
445
+
446
+ .prose-tight hr {
447
+ margin-block: 1.2em;
448
+ }