@prestack/thread-ui 0.1.10 → 0.1.11

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 (209) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/dist/ui/attach.js +6 -7
  3. package/dist/ui/compositions.d.ts +0 -8
  4. package/dist/ui/compositions.js +3 -166
  5. package/dist/ui/generators/routes.js +1 -0
  6. package/package.json +2 -2
  7. package/dist/ui/animations/anm_appear.ts +0 -13
  8. package/dist/ui/animations/anm_blur_in.ts +0 -19
  9. package/dist/ui/animations/anm_blur_out.ts +0 -18
  10. package/dist/ui/animations/anm_dismiss.ts +0 -18
  11. package/dist/ui/animations/anm_drop.ts +0 -19
  12. package/dist/ui/animations/anm_fall.ts +0 -18
  13. package/dist/ui/animations/anm_flash.ts +0 -18
  14. package/dist/ui/animations/anm_glow.ts +0 -16
  15. package/dist/ui/animations/anm_lift.ts +0 -16
  16. package/dist/ui/animations/anm_nudge.ts +0 -16
  17. package/dist/ui/animations/anm_pop_in.ts +0 -23
  18. package/dist/ui/animations/anm_pop_out.ts +0 -22
  19. package/dist/ui/animations/anm_press.ts +0 -12
  20. package/dist/ui/animations/anm_pulse.ts +0 -13
  21. package/dist/ui/animations/anm_rise.ts +0 -19
  22. package/dist/ui/animations/anm_shake.ts +0 -13
  23. package/dist/ui/animations/anm_slide_in_left.ts +0 -19
  24. package/dist/ui/animations/anm_slide_in_right.ts +0 -19
  25. package/dist/ui/animations/anm_slide_out_left.ts +0 -18
  26. package/dist/ui/animations/anm_slide_out_right.ts +0 -18
  27. package/dist/ui/animations/anm_spin.ts +0 -12
  28. package/dist/ui/animations/anm_swell.ts +0 -16
  29. package/dist/ui/animations/anm_wobble.ts +0 -24
  30. package/dist/ui/animations/anm_zoom_in.ts +0 -19
  31. package/dist/ui/animations/anm_zoom_out.ts +0 -18
  32. package/dist/ui/animations.ts +0 -308
  33. package/dist/ui/attach.ts +0 -553
  34. package/dist/ui/charts.tsx +0 -69
  35. package/dist/ui/checked.ts +0 -32
  36. package/dist/ui/collector.ts +0 -140
  37. package/dist/ui/compositions.ts +0 -613
  38. package/dist/ui/consent.ts +0 -55
  39. package/dist/ui/content.tsx +0 -27
  40. package/dist/ui/contrast.ts +0 -27
  41. package/dist/ui/controls.tsx +0 -25
  42. package/dist/ui/disclosure.tsx +0 -20
  43. package/dist/ui/dismiss-layer.ts +0 -87
  44. package/dist/ui/door.ts +0 -140
  45. package/dist/ui/drag.ts +0 -316
  46. package/dist/ui/elements/accordion.tsx +0 -47
  47. package/dist/ui/elements/accordion.works.ts +0 -66
  48. package/dist/ui/elements/aspect-ratio.tsx +0 -31
  49. package/dist/ui/elements/aspect-ratio.works.ts +0 -5
  50. package/dist/ui/elements/avatar.tsx +0 -34
  51. package/dist/ui/elements/avatar.works.ts +0 -16
  52. package/dist/ui/elements/badge.tsx +0 -33
  53. package/dist/ui/elements/badge.works.ts +0 -9
  54. package/dist/ui/elements/bars.tsx +0 -50
  55. package/dist/ui/elements/bars.works.ts +0 -29
  56. package/dist/ui/elements/box.tsx +0 -36
  57. package/dist/ui/elements/breadcrumb.tsx +0 -38
  58. package/dist/ui/elements/breadcrumb.works.ts +0 -24
  59. package/dist/ui/elements/button.tsx +0 -46
  60. package/dist/ui/elements/button.works.tsx +0 -52
  61. package/dist/ui/elements/column.tsx +0 -29
  62. package/dist/ui/elements/consent.tsx +0 -71
  63. package/dist/ui/elements/consent.works.tsx +0 -132
  64. package/dist/ui/elements/donut.tsx +0 -45
  65. package/dist/ui/elements/donut.works.ts +0 -42
  66. package/dist/ui/elements/each.tsx +0 -34
  67. package/dist/ui/elements/each.works.tsx +0 -82
  68. package/dist/ui/elements/empty.tsx +0 -33
  69. package/dist/ui/elements/field.tsx +0 -45
  70. package/dist/ui/elements/field.works.ts +0 -65
  71. package/dist/ui/elements/funnel.tsx +0 -50
  72. package/dist/ui/elements/funnel.works.ts +0 -37
  73. package/dist/ui/elements/gauge.tsx +0 -40
  74. package/dist/ui/elements/gauge.works.ts +0 -42
  75. package/dist/ui/elements/glyph.tsx +0 -30
  76. package/dist/ui/elements/glyph.works.tsx +0 -42
  77. package/dist/ui/elements/grid.tsx +0 -29
  78. package/dist/ui/elements/heatmap.tsx +0 -48
  79. package/dist/ui/elements/heatmap.works.ts +0 -24
  80. package/dist/ui/elements/hit-box.tsx +0 -47
  81. package/dist/ui/elements/hit-box.works.tsx +0 -576
  82. package/dist/ui/elements/image.tsx +0 -29
  83. package/dist/ui/elements/line-chart.tsx +0 -45
  84. package/dist/ui/elements/line-chart.works.ts +0 -41
  85. package/dist/ui/elements/link.tsx +0 -38
  86. package/dist/ui/elements/link.works.ts +0 -25
  87. package/dist/ui/elements/media.tsx +0 -57
  88. package/dist/ui/elements/menu.tsx +0 -51
  89. package/dist/ui/elements/menu.works.tsx +0 -154
  90. package/dist/ui/elements/money.tsx +0 -36
  91. package/dist/ui/elements/money.works.ts +0 -9
  92. package/dist/ui/elements/pagination.tsx +0 -39
  93. package/dist/ui/elements/pagination.works.ts +0 -20
  94. package/dist/ui/elements/progress.tsx +0 -34
  95. package/dist/ui/elements/progress.works.ts +0 -8
  96. package/dist/ui/elements/radio-group.tsx +0 -50
  97. package/dist/ui/elements/radio-group.works.ts +0 -33
  98. package/dist/ui/elements/row.tsx +0 -29
  99. package/dist/ui/elements/scatter.tsx +0 -42
  100. package/dist/ui/elements/scatter.works.ts +0 -38
  101. package/dist/ui/elements/select.tsx +0 -43
  102. package/dist/ui/elements/select.works.ts +0 -5
  103. package/dist/ui/elements/separator.tsx +0 -31
  104. package/dist/ui/elements/skeleton.tsx +0 -31
  105. package/dist/ui/elements/slider.tsx +0 -34
  106. package/dist/ui/elements/slider.works.ts +0 -5
  107. package/dist/ui/elements/sparkline.tsx +0 -37
  108. package/dist/ui/elements/sparkline.works.ts +0 -32
  109. package/dist/ui/elements/spinner.tsx +0 -33
  110. package/dist/ui/elements/stack.tsx +0 -29
  111. package/dist/ui/elements/stat.tsx +0 -36
  112. package/dist/ui/elements/stat.works.ts +0 -14
  113. package/dist/ui/elements/surface.tsx +0 -36
  114. package/dist/ui/elements/surface.works.ts +0 -9
  115. package/dist/ui/elements/table.tsx +0 -62
  116. package/dist/ui/elements/table.works.ts +0 -30
  117. package/dist/ui/elements/tabs.tsx +0 -47
  118. package/dist/ui/elements/tabs.works.ts +0 -84
  119. package/dist/ui/elements/text.tsx +0 -33
  120. package/dist/ui/elements/textarea.tsx +0 -38
  121. package/dist/ui/elements/textarea.works.ts +0 -5
  122. package/dist/ui/elements/time.tsx +0 -40
  123. package/dist/ui/elements/time.works.ts +0 -29
  124. package/dist/ui/elements/toggle.tsx +0 -34
  125. package/dist/ui/elements/toggle.works.ts +0 -5
  126. package/dist/ui/elements/tooltip.tsx +0 -40
  127. package/dist/ui/elements/tooltip.works.ts +0 -77
  128. package/dist/ui/elements/value.tsx +0 -38
  129. package/dist/ui/elements/value.works.ts +0 -9
  130. package/dist/ui/elements.ts +0 -127
  131. package/dist/ui/focus-scope.ts +0 -121
  132. package/dist/ui/fonts.ts +0 -355
  133. package/dist/ui/generators/dev.d.ts +0 -1
  134. package/dist/ui/generators/dev.js +0 -62
  135. package/dist/ui/generators/dev.ts +0 -75
  136. package/dist/ui/generators/elements.ts +0 -796
  137. package/dist/ui/generators/i18n.ts +0 -283
  138. package/dist/ui/generators/icons.ts +0 -207
  139. package/dist/ui/generators/react.ts +0 -267
  140. package/dist/ui/generators/routes.ts +0 -847
  141. package/dist/ui/generators/show.ts +0 -261
  142. package/dist/ui/generators/styles.ts +0 -677
  143. package/dist/ui/generators/variants.ts +0 -196
  144. package/dist/ui/i18n/catalogs/en.ts +0 -191
  145. package/dist/ui/i18n/format.ts +0 -221
  146. package/dist/ui/i18n/locales.ts +0 -33
  147. package/dist/ui/i18n/parse.ts +0 -315
  148. package/dist/ui/i18n/translator.ts +0 -31
  149. package/dist/ui/i18n/types.ts +0 -96
  150. package/dist/ui/icons.ts +0 -331
  151. package/dist/ui/islands/map.ts +0 -58
  152. package/dist/ui/localizations.ts +0 -75
  153. package/dist/ui/material.ts +0 -236
  154. package/dist/ui/materials/mat_bordered.ts +0 -13
  155. package/dist/ui/materials/mat_ceramic.ts +0 -13
  156. package/dist/ui/materials/mat_clay.ts +0 -13
  157. package/dist/ui/materials/mat_elevated.ts +0 -24
  158. package/dist/ui/materials/mat_flat.ts +0 -34
  159. package/dist/ui/materials/mat_glass.ts +0 -20
  160. package/dist/ui/materials/mat_lit.ts +0 -13
  161. package/dist/ui/materials/mat_moulded.ts +0 -11
  162. package/dist/ui/materials.ts +0 -197
  163. package/dist/ui/modes.ts +0 -44
  164. package/dist/ui/navigation.tsx +0 -29
  165. package/dist/ui/positioning.ts +0 -90
  166. package/dist/ui/presented.tsx +0 -119
  167. package/dist/ui/provider.tsx +0 -184
  168. package/dist/ui/render-loop.ts +0 -133
  169. package/dist/ui/roving-focus.ts +0 -161
  170. package/dist/ui/screens.ts +0 -141
  171. package/dist/ui/scroll-lock.ts +0 -28
  172. package/dist/ui/series.ts +0 -97
  173. package/dist/ui/signals.ts +0 -386
  174. package/dist/ui/styleguide.ts +0 -231
  175. package/dist/ui/styleguides.ts +0 -374
  176. package/dist/ui/themes.ts +0 -22
  177. package/dist/ui/token.ts +0 -78
  178. package/dist/ui/tokens/shadow.ts +0 -25
  179. package/dist/ui/tokens.ts +0 -234
  180. package/dist/ui/validators.ts +0 -232
  181. package/dist/ui/variant.ts +0 -349
  182. package/dist/ui/variants/var_avatar-round.ts +0 -14
  183. package/dist/ui/variants/var_bubble-me.ts +0 -14
  184. package/dist/ui/variants/var_bubble-them.ts +0 -13
  185. package/dist/ui/variants/var_button-border.ts +0 -76
  186. package/dist/ui/variants/var_button-cta.ts +0 -76
  187. package/dist/ui/variants/var_button-destructive-ghost.ts +0 -72
  188. package/dist/ui/variants/var_button-destructive.ts +0 -76
  189. package/dist/ui/variants/var_button-fill.ts +0 -76
  190. package/dist/ui/variants/var_button-ghost.ts +0 -72
  191. package/dist/ui/variants/var_button-glass.ts +0 -55
  192. package/dist/ui/variants/var_button-normal.ts +0 -76
  193. package/dist/ui/variants/var_button-quiet.ts +0 -74
  194. package/dist/ui/variants/var_card.ts +0 -17
  195. package/dist/ui/variants/var_chip.ts +0 -13
  196. package/dist/ui/variants/var_choice.ts +0 -15
  197. package/dist/ui/variants/var_framed.ts +0 -10
  198. package/dist/ui/variants/var_glyph-plain.ts +0 -11
  199. package/dist/ui/variants/var_input.ts +0 -43
  200. package/dist/ui/variants/var_link-inline.ts +0 -29
  201. package/dist/ui/variants/var_list-row.ts +0 -34
  202. package/dist/ui/variants/var_rule.ts +0 -10
  203. package/dist/ui/variants/var_skeleton-block.ts +0 -12
  204. package/dist/ui/variants/var_spinner-turning.ts +0 -12
  205. package/dist/ui/variants/var_stat-tile.ts +0 -13
  206. package/dist/ui/variants/var_tab-bar.ts +0 -15
  207. package/dist/ui/variants/var_tap-target.ts +0 -25
  208. package/dist/ui/variants.ts +0 -64
  209. package/dist/ui/wrappers.tsx +0 -429
package/dist/ui/fonts.ts DELETED
@@ -1,355 +0,0 @@
1
- import type { Threaded } from '@prestack/thread/core/thread'
2
-
3
- import { sheeted, type Holds } from './token.ts'
4
-
5
- export const FACES = ['body', 'heading', 'display', 'mono'] as const
6
- export type Face = (typeof FACES)[number]
7
-
8
- export interface FontFamily {
9
-
10
- readonly name: string
11
-
12
- readonly module: string
13
-
14
- readonly file: string
15
-
16
- readonly weight: string
17
-
18
- readonly range: string
19
-
20
- readonly licence: string
21
-
22
- readonly fallback: string
23
- }
24
-
25
- export interface FontSet {
26
- readonly name: string
27
-
28
- readonly families: Readonly<Partial<Record<Face, FontFamily>>>
29
- }
30
-
31
- const SANS_FALLBACK = 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif'
32
- const SERIF_FALLBACK = 'ui-serif, Georgia, Cambria, Times New Roman, serif'
33
- const MONO_FALLBACK = 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace'
34
-
35
- const LATIN =
36
- 'U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD'
37
-
38
- const OFL = 'SIL Open Font Licence 1.1'
39
-
40
- const INTER: FontFamily = {
41
- name: 'Inter Variable',
42
- module: '@fontsource-variable/inter',
43
- file: 'files/inter-latin-wght-normal.woff2',
44
- weight: '100 900',
45
- range: LATIN,
46
- licence: OFL,
47
- fallback: SANS_FALLBACK,
48
- }
49
-
50
- const JETBRAINS_MONO: FontFamily = {
51
- name: 'JetBrains Mono Variable',
52
- module: '@fontsource-variable/jetbrains-mono',
53
- file: 'files/jetbrains-mono-latin-wght-normal.woff2',
54
- weight: '100 800',
55
- range: LATIN,
56
- licence: OFL,
57
- fallback: MONO_FALLBACK,
58
- }
59
-
60
- const WORK_SANS: FontFamily = {
61
- name: 'Work Sans Variable',
62
- module: '@fontsource-variable/work-sans',
63
- file: 'files/work-sans-latin-wght-normal.woff2',
64
- weight: '100 900',
65
- range: LATIN,
66
- licence: OFL,
67
- fallback: SANS_FALLBACK,
68
- }
69
-
70
- const SPACE_GROTESK: FontFamily = {
71
- name: 'Space Grotesk Variable',
72
- module: '@fontsource-variable/space-grotesk',
73
- file: 'files/space-grotesk-latin-wght-normal.woff2',
74
- weight: '300 700',
75
- range: LATIN,
76
- licence: OFL,
77
- fallback: SANS_FALLBACK,
78
- }
79
-
80
- const ROBOTO_MONO: FontFamily = {
81
- name: 'Roboto Mono Variable',
82
- module: '@fontsource-variable/roboto-mono',
83
- file: 'files/roboto-mono-latin-wght-normal.woff2',
84
- weight: '100 700',
85
- range: LATIN,
86
- licence: OFL,
87
- fallback: MONO_FALLBACK,
88
- }
89
-
90
- const SOURCE_SERIF: FontFamily = {
91
- name: 'Source Serif 4 Variable',
92
- module: '@fontsource-variable/source-serif-4',
93
- file: 'files/source-serif-4-latin-wght-normal.woff2',
94
- weight: '200 900',
95
- range: LATIN,
96
- licence: OFL,
97
- fallback: SERIF_FALLBACK,
98
- }
99
-
100
- const PLAYFAIR_DISPLAY: FontFamily = {
101
- name: 'Playfair Display Variable',
102
- module: '@fontsource-variable/playfair-display',
103
- file: 'files/playfair-display-latin-wght-normal.woff2',
104
- weight: '400 900',
105
- range: LATIN,
106
- licence: OFL,
107
- fallback: SERIF_FALLBACK,
108
- }
109
-
110
- const SOURCE_CODE_PRO: FontFamily = {
111
- name: 'Source Code Pro Variable',
112
- module: '@fontsource-variable/source-code-pro',
113
- file: 'files/source-code-pro-latin-wght-normal.woff2',
114
- weight: '200 900',
115
- range: LATIN,
116
- licence: OFL,
117
- fallback: MONO_FALLBACK,
118
- }
119
-
120
- const LIBRE_BASKERVILLE: FontFamily = {
121
- name: 'Libre Baskerville Variable',
122
- module: '@fontsource-variable/libre-baskerville',
123
- file: 'files/libre-baskerville-latin-wght-normal.woff2',
124
- weight: '400 700',
125
- range: LATIN,
126
- licence: OFL,
127
- fallback: SERIF_FALLBACK,
128
- }
129
-
130
- const SETS: Readonly<Record<string, FontSet>> = {
131
-
132
- inter: {
133
- name: 'inter',
134
- families: { body: INTER, heading: INTER, display: INTER, mono: JETBRAINS_MONO },
135
- },
136
-
137
- grotesk: {
138
- name: 'grotesk',
139
- families: { body: WORK_SANS, heading: SPACE_GROTESK, display: SPACE_GROTESK, mono: ROBOTO_MONO },
140
- },
141
-
142
- editorial: {
143
- name: 'editorial',
144
- families: { body: SOURCE_SERIF, heading: SOURCE_SERIF, display: PLAYFAIR_DISPLAY, mono: SOURCE_CODE_PRO },
145
- },
146
-
147
- libre: {
148
- name: 'libre',
149
- families: { body: LIBRE_BASKERVILLE, heading: LIBRE_BASKERVILLE, display: LIBRE_BASKERVILLE, mono: SOURCE_CODE_PRO },
150
- },
151
- }
152
-
153
- const SET_REGISTRY = new Map<string, FontSet>(Object.entries(SETS))
154
-
155
- export function defineFontSet(set: FontSet): void {
156
- if (SET_REGISTRY.has(set.name)) throw new Error(`font set "${set.name}" is already registered`)
157
-
158
- const faces = new Set<string>(FACES)
159
- for (const face of Object.keys(set.families).sort()) {
160
- if (!faces.has(face)) {
161
- throw new Error(
162
- `font set "${set.name}" serves "${face}", which is not a face. Faces: ${[...FACES].sort().join(', ')}`,
163
- )
164
- }
165
- }
166
-
167
- SET_REGISTRY.set(set.name, set)
168
- }
169
-
170
- export function fontSets(): readonly FontSet[] {
171
- return [...SET_REGISTRY.values()].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))
172
- }
173
-
174
- export function fontSet(name: string): FontSet | undefined {
175
- return SET_REGISTRY.get(name)
176
- }
177
-
178
- export function fontFaces(): readonly string[] {
179
- return [...FACES].sort()
180
- }
181
-
182
- export function fontModules(): readonly string[] {
183
- const modules = new Set<string>()
184
- for (const set of fontSets()) {
185
- for (const family of Object.values(set.families)) modules.add(family.module)
186
- }
187
- return [...modules].sort()
188
- }
189
-
190
- export function fontIn(set: string, face: string): FontFamily | undefined {
191
- return SET_REGISTRY.get(set)?.families[face as Face]
192
- }
193
-
194
- export function fontVariable(face: string): string {
195
- return `--thread-font-${face}`
196
- }
197
-
198
- export function fontStack(family: FontFamily): string {
199
- return `'${family.name}', ${family.fallback}`
200
- }
201
-
202
- const GENERIC: Readonly<Record<Face, string>> = {
203
- body: 'sans-serif',
204
- heading: 'sans-serif',
205
- display: 'sans-serif',
206
- mono: 'monospace',
207
- }
208
-
209
- export function fontFor(face: Face): string {
210
- return `var(${fontVariable(face)}, ${GENERIC[face]})`
211
- }
212
-
213
- export interface FontRole {
214
- readonly face: Face
215
-
216
- readonly size: string
217
-
218
- readonly weight: string
219
-
220
- readonly leading: string
221
-
222
- readonly tracking: string
223
-
224
- readonly case?: 'uppercase' | 'none'
225
-
226
- readonly style?: 'italic' | 'normal'
227
- }
228
-
229
- type Row = Omit<Threaded, 'at'> & {
230
- readonly section?: string
231
- readonly is?: string
232
- readonly sets?: Readonly<Record<string, string>>
233
- }
234
-
235
- const sectionOf = (face: string, id: string): string => {
236
- if (id === 'mono') return 'fixed-width'
237
- if (face === 'body') return 'reading'
238
- return 'headline'
239
- }
240
-
241
- const role = <Id extends string>(
242
- id: Id,
243
- sets: FontRole,
244
- describes: string,
245
- ): { readonly id: Id; readonly sets: FontRole; readonly describes: string } => ({ id, sets, describes })
246
-
247
- const ROLES = [
248
- role('display', { face: 'display', size: '40px', weight: '700', leading: '1.15', tracking: '-0.02em' },
249
- 'The one line a screen is built around, used once. Large enough that its leading has to be pulled in and its letters set tight, which is why it is its own role rather than a bigger heading.'),
250
- role('title', { face: 'heading', size: '32px', weight: '700', leading: '1.15', tracking: '-0.02em' },
251
- 'What the page is called. The first wording a reader resolves after the display line, and the last one allowed to be this heavy.'),
252
- role('heading', { face: 'heading', size: '24px', weight: '600', leading: '1.15', tracking: '-0.02em' },
253
- 'What a section is called — the size that gives a screen its structure, and the one a reader scans for.'),
254
- role('subheading', { face: 'heading', size: '20px', weight: '600', leading: '1.5', tracking: '0' },
255
- 'What a part of a section is called. Set at running leading rather than tight, because at this size the lines are read rather than scanned.'),
256
- role('lead', { face: 'body', size: '20px', weight: '400', leading: '1.5', tracking: '0' },
257
- 'The paragraph that opens a page — body wording at a heading\'s size, so it carries weight without being a heading.'),
258
- role('body', { face: 'body', size: '16px', weight: '400', leading: '1.5', tracking: '0' },
259
- 'Running text, and the size every other role is judged against. What wording is set in unless something says otherwise.'),
260
- role('label', { face: 'body', size: '13px', weight: '500', leading: '1.5', tracking: '0' },
261
- 'Wording attached to a control — the name above a field, the words on a button. Slightly forward of body, because a label names a thing rather than describing it.'),
262
- role('caption', { face: 'body', size: '12px', weight: '400', leading: '1.5', tracking: '0.02em' },
263
- 'The small print — a hint under a field, a timestamp, a legal line. Its letters are opened up, because small type set tight closes into a block.'),
264
- role('overline', { face: 'body', size: '12px', weight: '600', leading: '1.5', tracking: '0.02em', case: 'uppercase' },
265
- 'A micro label above the thing it names — a category, a section marker. The one role forced to capitals, which is what makes it read as a marker rather than a sentence.'),
266
- role('mono', { face: 'mono', size: '13px', weight: '400', leading: '1.5', tracking: '0' },
267
- 'Wording where every character asks the same width — code, keys, anything meant to be compared column by column.'),
268
- ] as const
269
-
270
- export type FontRoleId = (typeof ROLES)[number]['id']
271
-
272
- export const ROLE_IDS: readonly FontRoleId[] = ROLES.map((one) => one.id)
273
-
274
- export const DEFAULT_ROLE: FontRoleId = 'body'
275
-
276
- export const SET_ROW = 'family-set'
277
-
278
- export const holds: readonly Row[] = [
279
-
280
- {
281
- id: SET_ROW,
282
- section: 'the set',
283
- is: 'inter',
284
- describes:
285
- 'Which set of families every face is drawn from. One name, because a set provides all four faces at once — changing it changes the whole app rather than one heading.',
286
- version: 1,
287
- },
288
- ...ROLES.map((one): Row => ({
289
- id: one.id,
290
- section: sectionOf(one.sets.face, one.id),
291
- sets: one.sets as unknown as Readonly<Record<string, string>>,
292
- describes: one.describes,
293
- version: 1,
294
- })),
295
- ]
296
-
297
- export const FONTS = {
298
- id: 'font',
299
- at: 'thread/ui/fonts.ts',
300
- describes:
301
- 'Every way wording is set, and the only place that is decided. A role names one of the four faces a set provides and states the size, weight, leading, tracking and case that job is set at — so `Text.body` needs to be told nothing beyond which job it is doing. It holds no colour and shifts under no mode or theme: colour belongs to the material or variant the wording is worn by, where a coloured control can overrule the theme it sits in. The style guide holds no font, because a font is not a token — this file is the source, and an app changes its typography by changing a row here or by naming a different set.',
302
- version: 1,
303
- cites: [
304
- {
305
- on: '2026-08-28',
306
- said: 'Styleguide DOES NOT DEFINE FONTS. It takes care of token values. Let\'s leave fonts.ts as the SSOT for font family per type + size and appearence per type for the entire app. So UI puts Text.body("this is the label") and it reads from fonts to see what is the body, the font, the size, everything.',
307
- },
308
- {
309
- on: '2026-08-28',
310
- said: 'Fonts now are SSOT for fonts. So font is not a token anymore.',
311
- },
312
- ],
313
- holds,
314
- } satisfies Threaded & { readonly holds: readonly Row[] }
315
-
316
- export function classOfRole(id: string): string {
317
- return `f-${id}`
318
- }
319
-
320
- export function settingsOf(id: string, role: FontRole): Readonly<Record<string, Holds>> {
321
- return {
322
- fontFamily: sheeted(id, `var(${fontVariable(role.face)})`),
323
- fontSize: sheeted(id, role.size),
324
- fontWeight: sheeted(id, role.weight),
325
- lineHeight: sheeted(id, role.leading),
326
- letterSpacing: sheeted(id, role.tracking),
327
- ...(role.case === undefined ? {} : { textTransform: sheeted(id, role.case) }),
328
- ...(role.style === undefined ? {} : { fontStyle: sheeted(id, role.style) }),
329
- }
330
- }
331
-
332
- export function roleClass(is: FontRoleId | undefined, className: string | undefined): string {
333
- const own = classOfRole(is ?? DEFAULT_ROLE)
334
- return className === undefined || className === '' ? own : `${own} ${className}`
335
- }
336
-
337
- export function familyFor(set: FontSet, face: string, by: string): FontFamily {
338
- const found = set.families[face as Face]
339
- if (found !== undefined) return found
340
- const has = Object.keys(set.families).sort().map((one) => `\`${one}\``)
341
- throw new Error(
342
- `\`${by}\` is set in the \`${face}\` face, and the \`${set.name}\` set does not provide one. ` +
343
- `It provides ${has.join(', ')}. Name a face the set has, or give the set that one.`,
344
- )
345
- }
346
-
347
- export function setNamed(name: string): FontSet {
348
- const found = SET_REGISTRY.get(name)
349
- if (found !== undefined) return found
350
- const has = [...SET_REGISTRY.keys()].sort().map((one) => `\`${one}\``)
351
- throw new Error(
352
- `\`${name}\` is named as the font set, and no set by that name is registered. ` +
353
- `The registered sets are ${has.join(', ')}.`,
354
- )
355
- }
@@ -1 +0,0 @@
1
- export declare function unrunnable(program: string): string;
@@ -1,62 +0,0 @@
1
- import { releases, starts } from '@prestack/thread/integrations/cli';
2
- import { basename } from 'node:path';
3
- import { argv, stdout } from 'node:process';
4
- import { batched, generators, settling } from '@prestack/thread/core/chain';
5
- import { existsSync, readFileSync } from '@prestack/thread/integrations/disk';
6
- import { exit, invoked } from '@prestack/thread/core/invoked';
7
- import { named } from '@prestack/thread/core/scope';
8
- import { findTree } from '@prestack/thread/core/tree';
9
- import { programOf } from '@prestack/thread/integrations/target';
10
- const SERVER = 'next';
11
- const SHIP = '--ship';
12
- const ENTRY = 'dev';
13
- const SHIPPED = 'build';
14
- const GATE = 'thread gate';
15
- const say = (line) => {
16
- stdout.write(line);
17
- };
18
- export function unrunnable(program) {
19
- return (program + ' is not installed here, so there is nothing to serve this app with. ' +
20
- named('ui') + ' brings it: run thread attach ' + named('ui') + ' and try again.');
21
- }
22
- async function run() {
23
- const tree = findTree();
24
- const shipping = argv.includes(SHIP);
25
- const entry = shipping ? SHIPPED : ENTRY;
26
- const found = programOf(SERVER, tree.at, existsSync, (path) => readFileSync(path, 'utf8'));
27
- if (found === undefined) {
28
- say('thread: ' + unrunnable(SERVER) + '\n');
29
- return 1;
30
- }
31
- const settled = settling(tree.at, await generators(tree));
32
- for (const said of settled.ran)
33
- if (said.trim() !== '')
34
- say(said + '\n');
35
- if (settled.unsettled.length > 0) {
36
- say('thread: ' + settled.unsettled.join(', ') + ' would not settle after ' + String(settled.rounds) + ' rounds, ' +
37
- 'so what this tree declares and what is written from it still disagree. Nothing is served over that.\n');
38
- return 1;
39
- }
40
- say('thread: ' + basename(tree.at) + ' settled in ' + String(settled.rounds) + ' round(s); running the gate\n');
41
- const gated = batched(tree.at, [GATE]);
42
- for (const one of gated)
43
- if (one.said !== '')
44
- say(one.said + '\n');
45
- if (!gated.every((one) => one.ok)) {
46
- say('thread: the gate refused this tree, and nothing is served over a red gate. What it refused is printed above.\n');
47
- return 1;
48
- }
49
- say('thread: the gate passed; running ' + SERVER + ' ' + entry + '\n');
50
- const extra = argv.slice(2).filter((one) => one !== SHIP);
51
- if (!shipping)
52
- releases();
53
- const [program = '', ...lead] = found;
54
- const held = starts(program, [...lead, entry, ...extra], { at: tree.at, shows: true });
55
- if (!held.there) {
56
- say('thread: could not start ' + SERVER + ' ' + entry + ': ' + held.why + '\n');
57
- return 1;
58
- }
59
- return held.code;
60
- }
61
- if (invoked(import.meta.url))
62
- exit(await run());
@@ -1,75 +0,0 @@
1
- import { releases, starts } from '@prestack/thread/integrations/cli'
2
- import { basename } from 'node:path'
3
- import { argv, stdout } from 'node:process'
4
-
5
- import { batched, generators, settling } from '@prestack/thread/core/chain'
6
- import { existsSync, readFileSync } from '@prestack/thread/integrations/disk'
7
- import { exit, invoked } from '@prestack/thread/core/invoked'
8
- import { named } from '@prestack/thread/core/scope'
9
- import { findTree } from '@prestack/thread/core/tree'
10
- import { programOf } from '@prestack/thread/integrations/target'
11
-
12
- const SERVER = 'next'
13
-
14
- const SHIP = '--ship'
15
-
16
- const ENTRY = 'dev'
17
-
18
- const SHIPPED = 'build'
19
-
20
- const GATE = 'thread gate'
21
-
22
- const say = (line: string): void => {
23
- stdout.write(line)
24
- }
25
-
26
- export function unrunnable(program: string): string {
27
- return (
28
- program + ' is not installed here, so there is nothing to serve this app with. ' +
29
- named('ui') + ' brings it: run thread attach ' + named('ui') + ' and try again.'
30
- )
31
- }
32
-
33
- async function run(): Promise<number> {
34
- const tree = findTree()
35
- const shipping = argv.includes(SHIP)
36
- const entry = shipping ? SHIPPED : ENTRY
37
-
38
- const found = programOf(SERVER, tree.at, existsSync, (path) => readFileSync(path, 'utf8'))
39
- if (found === undefined) {
40
- say('thread: ' + unrunnable(SERVER) + '\n')
41
- return 1
42
- }
43
-
44
- const settled = settling(tree.at, await generators(tree))
45
- for (const said of settled.ran) if (said.trim() !== '') say(said + '\n')
46
-
47
- if (settled.unsettled.length > 0) {
48
- say(
49
- 'thread: ' + settled.unsettled.join(', ') + ' would not settle after ' + String(settled.rounds) + ' rounds, ' +
50
- 'so what this tree declares and what is written from it still disagree. Nothing is served over that.\n',
51
- )
52
- return 1
53
- }
54
-
55
- say('thread: ' + basename(tree.at) + ' settled in ' + String(settled.rounds) + ' round(s); running the gate\n')
56
- const gated = batched(tree.at, [GATE])
57
- for (const one of gated) if (one.said !== '') say(one.said + '\n')
58
- if (!gated.every((one) => one.ok)) {
59
- say('thread: the gate refused this tree, and nothing is served over a red gate. What it refused is printed above.\n')
60
- return 1
61
- }
62
-
63
- say('thread: the gate passed; running ' + SERVER + ' ' + entry + '\n')
64
- const extra = argv.slice(2).filter((one) => one !== SHIP)
65
- if (!shipping) releases()
66
- const [program = '', ...lead] = found
67
- const held = starts(program, [...lead, entry, ...extra], { at: tree.at, shows: true })
68
- if (!held.there) {
69
- say('thread: could not start ' + SERVER + ' ' + entry + ': ' + held.why + '\n')
70
- return 1
71
- }
72
- return held.code
73
- }
74
-
75
- if (invoked(import.meta.url)) exit(await run())