@krizaka/ui 3.51.0 → 3.52.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 (215) hide show
  1. package/dist/argument-card.js +3 -3
  2. package/dist/blocks.css +185 -0
  3. package/dist/chunk-YATTFMDV.js +45 -0
  4. package/dist/chunk-YATTFMDV.js.map +1 -0
  5. package/dist/glossary-term.d.ts +12 -0
  6. package/dist/glossary-term.js +16 -0
  7. package/dist/glossary-term.js.map +1 -0
  8. package/dist/glossary.d.ts +20 -0
  9. package/dist/glossary.js +17 -0
  10. package/dist/glossary.js.map +1 -0
  11. package/dist/index.js +7 -7
  12. package/dist/kpi-explained.d.ts +66 -0
  13. package/dist/kpi-explained.js +84 -0
  14. package/dist/kpi-explained.js.map +1 -0
  15. package/dist/next-actions.d.ts +27 -0
  16. package/dist/next-actions.js +27 -0
  17. package/dist/next-actions.js.map +1 -0
  18. package/dist/text-style/server.d.ts +63 -0
  19. package/dist/text-style/server.js +109 -0
  20. package/dist/text-style/server.js.map +1 -0
  21. package/dist/text-style.d.ts +149 -0
  22. package/dist/text-style.js +399 -0
  23. package/dist/text-style.js.map +1 -0
  24. package/dist/tooltip.js +5 -37
  25. package/dist/tooltip.js.map +1 -1
  26. package/package.json +69 -5
  27. package/registry/account-menu.json +1 -1
  28. package/registry/account-settings.json +1 -1
  29. package/registry/achievement.json +1 -1
  30. package/registry/action-bar.json +1 -1
  31. package/registry/activity-feed.json +1 -1
  32. package/registry/agenda.json +1 -1
  33. package/registry/alert.json +1 -1
  34. package/registry/anatomy-plate.json +1 -1
  35. package/registry/app-header.json +1 -1
  36. package/registry/app-shell.json +1 -1
  37. package/registry/argument-card.json +1 -1
  38. package/registry/audio-player.json +1 -1
  39. package/registry/auth-layout.json +1 -1
  40. package/registry/avatar.json +1 -1
  41. package/registry/badge.json +1 -1
  42. package/registry/bird-plate.json +1 -1
  43. package/registry/button.json +1 -1
  44. package/registry/captcha.json +1 -1
  45. package/registry/card-grid.json +1 -1
  46. package/registry/card.json +1 -1
  47. package/registry/catalogue-page.json +1 -1
  48. package/registry/changelog-page.json +1 -1
  49. package/registry/chat.json +1 -1
  50. package/registry/checkbox.json +1 -1
  51. package/registry/chip-link.json +1 -1
  52. package/registry/chip-row.json +1 -1
  53. package/registry/chip.json +1 -1
  54. package/registry/choice-grid.json +1 -1
  55. package/registry/code-block.json +1 -1
  56. package/registry/combobox.json +1 -1
  57. package/registry/command.json +1 -1
  58. package/registry/comparison-table.json +1 -1
  59. package/registry/component-page.json +1 -1
  60. package/registry/confirm-button.json +1 -1
  61. package/registry/contact-page.json +1 -1
  62. package/registry/continue-prompt.json +1 -1
  63. package/registry/countdown.json +1 -1
  64. package/registry/cover-hero.json +1 -1
  65. package/registry/cta-panel.json +1 -1
  66. package/registry/dashboard-layout.json +1 -1
  67. package/registry/data-table.json +1 -1
  68. package/registry/date-picker.json +2 -2
  69. package/registry/decision-list.json +1 -1
  70. package/registry/description-list.json +1 -1
  71. package/registry/detail-layout.json +1 -1
  72. package/registry/dialog.json +1 -1
  73. package/registry/docs-article-page.json +1 -1
  74. package/registry/docs-hub-page.json +1 -1
  75. package/registry/docs-layout.json +1 -1
  76. package/registry/docs-nav.json +1 -1
  77. package/registry/document-viewer.json +1 -1
  78. package/registry/drop-overlay.json +1 -1
  79. package/registry/dropdown-menu.json +1 -1
  80. package/registry/elephant.json +2 -2
  81. package/registry/empty-state.json +1 -1
  82. package/registry/engine-flow.json +1 -1
  83. package/registry/error-page.json +1 -1
  84. package/registry/examples/glossary/shop-terms.d.ts +4 -0
  85. package/registry/examples/glossary/shop-terms.js +11 -0
  86. package/registry/examples/glossary/shop-terms.tsx +5 -0
  87. package/registry/examples/glossary-term/inline.d.ts +4 -0
  88. package/registry/examples/glossary-term/inline.js +15 -0
  89. package/registry/examples/glossary-term/inline.tsx +5 -0
  90. package/registry/examples/kpi-explained/founder-cockpit.d.ts +4 -0
  91. package/registry/examples/kpi-explained/founder-cockpit.js +11 -0
  92. package/registry/examples/kpi-explained/founder-cockpit.tsx +5 -0
  93. package/registry/examples/kpi-explained/salon-month.d.ts +4 -0
  94. package/registry/examples/kpi-explained/salon-month.js +11 -0
  95. package/registry/examples/kpi-explained/salon-month.tsx +5 -0
  96. package/registry/examples/next-actions/shop-owner.d.ts +4 -0
  97. package/registry/examples/next-actions/shop-owner.js +11 -0
  98. package/registry/examples/next-actions/shop-owner.tsx +5 -0
  99. package/registry/examples/text-style/compact-toolbar.d.ts +4 -0
  100. package/registry/examples/text-style/compact-toolbar.js +28 -0
  101. package/registry/examples/text-style/compact-toolbar.tsx +21 -0
  102. package/registry/examples/text-style/product-price.d.ts +4 -0
  103. package/registry/examples/text-style/product-price.js +26 -0
  104. package/registry/examples/text-style/product-price.tsx +17 -0
  105. package/registry/examples/text-style/storefront-title.d.ts +4 -0
  106. package/registry/examples/text-style/storefront-title.js +36 -0
  107. package/registry/examples/text-style/storefront-title.tsx +22 -0
  108. package/registry/field.json +1 -1
  109. package/registry/file-upload.json +2 -2
  110. package/registry/filter-bar.json +1 -1
  111. package/registry/flock.json +1 -1
  112. package/registry/footnote.json +1 -1
  113. package/registry/force-update-screen.json +1 -1
  114. package/registry/form.json +2 -2
  115. package/registry/gallery-page.json +1 -1
  116. package/registry/genui.json +2 -2
  117. package/registry/glossary-term.json +144 -0
  118. package/registry/glossary.json +137 -0
  119. package/registry/glow-card.json +1 -1
  120. package/registry/goal-gauge.json +1 -1
  121. package/registry/how-it-works-page.json +1 -1
  122. package/registry/image-cropper.json +1 -1
  123. package/registry/index.json +168 -11
  124. package/registry/iso.json +1 -1
  125. package/registry/kanban.json +1 -1
  126. package/registry/kbd.json +1 -1
  127. package/registry/kpi-explained.json +364 -0
  128. package/registry/landing-page.json +1 -1
  129. package/registry/landscape.json +1 -1
  130. package/registry/language-switch.json +1 -1
  131. package/registry/legal-page.json +1 -1
  132. package/registry/link-card.json +1 -1
  133. package/registry/list.json +1 -1
  134. package/registry/loader.json +1 -1
  135. package/registry/longform-page.json +1 -1
  136. package/registry/maintenance-screen.json +1 -1
  137. package/registry/map.json +2 -2
  138. package/registry/markdown.json +1 -1
  139. package/registry/marketing-layout.json +1 -1
  140. package/registry/marquee.json +1 -1
  141. package/registry/mascot-quote.json +1 -1
  142. package/registry/mascot-state.json +1 -1
  143. package/registry/mascots.json +1 -1
  144. package/registry/match-dialog.json +1 -1
  145. package/registry/media-capture.json +1 -1
  146. package/registry/media-gallery.json +1 -1
  147. package/registry/media-grid.json +1 -1
  148. package/registry/meta-row.json +1 -1
  149. package/registry/meter.json +1 -1
  150. package/registry/nav-bar.json +2 -2
  151. package/registry/next-actions.json +142 -0
  152. package/registry/number-ticker.json +1 -1
  153. package/registry/opening-hours.json +1 -1
  154. package/registry/page-header.json +1 -1
  155. package/registry/page-hero.json +1 -1
  156. package/registry/page-index.json +1 -1
  157. package/registry/page.json +1 -1
  158. package/registry/pagination.json +1 -1
  159. package/registry/photo-grid.json +1 -1
  160. package/registry/pointer-light.json +1 -1
  161. package/registry/popover.json +1 -1
  162. package/registry/pricing-page.json +1 -1
  163. package/registry/product-page.json +1 -1
  164. package/registry/profile-card.json +1 -1
  165. package/registry/progress.json +1 -1
  166. package/registry/promise-card.json +1 -1
  167. package/registry/radio-group.json +1 -1
  168. package/registry/rail-nav.json +2 -2
  169. package/registry/recipes.json +1 -1
  170. package/registry/router.json +1 -1
  171. package/registry/scroll-stage.json +1 -1
  172. package/registry/search-field.json +1 -1
  173. package/registry/section-backdrop.json +1 -1
  174. package/registry/separator.json +1 -1
  175. package/registry/service-card.json +1 -1
  176. package/registry/settings-layout.json +1 -1
  177. package/registry/showcase.json +1 -1
  178. package/registry/site-footer.json +2 -2
  179. package/registry/sites.json +1 -1
  180. package/registry/skeleton.json +1 -1
  181. package/registry/skip-link.json +1 -1
  182. package/registry/slider.json +1 -1
  183. package/registry/slot-picker.json +1 -1
  184. package/registry/slot.json +1 -1
  185. package/registry/specimen-tag.json +1 -1
  186. package/registry/spinner.json +1 -1
  187. package/registry/split-view.json +1 -1
  188. package/registry/stage-banner.json +1 -1
  189. package/registry/stat.json +1 -1
  190. package/registry/status-page.json +1 -1
  191. package/registry/step-progress.json +1 -1
  192. package/registry/step-showcase.json +1 -1
  193. package/registry/stepper.json +1 -1
  194. package/registry/sticky-action.json +1 -1
  195. package/registry/swipe-deck.json +1 -1
  196. package/registry/switch.json +1 -1
  197. package/registry/tabs.json +1 -1
  198. package/registry/tag-input.json +1 -1
  199. package/registry/tag-selector.json +1 -1
  200. package/registry/taped-photo.json +1 -1
  201. package/registry/terminal-replay.json +1 -1
  202. package/registry/text-style.json +378 -0
  203. package/registry/theme.json +1 -1
  204. package/registry/toast.json +1 -1
  205. package/registry/toc.json +1 -1
  206. package/registry/tooltip.json +1 -1
  207. package/registry/tree-view.json +1 -1
  208. package/registry/update-prompt.json +1 -1
  209. package/registry/upload-queue.json +1 -1
  210. package/registry/verified-badge.json +1 -1
  211. package/registry/vertical-video.json +2 -2
  212. package/registry/video-player.json +1 -1
  213. package/registry/video-trimmer.json +1 -1
  214. package/registry/virtual.json +1 -1
  215. package/registry/waveform.json +1 -1
@@ -0,0 +1,63 @@
1
+ import * as React from 'react';
2
+ import { CSSProperties } from 'react';
3
+
4
+ type StyledTextProps<T extends React.ElementType = "p"> = {
5
+ /** The element drawn: `h1`…`h6`, `p`, `span`, `div`. */
6
+ as?: T;
7
+ /** The stored text style — validated here: anything invalid draws the default. */
8
+ value?: unknown;
9
+ /** Merged after the style's own class. */
10
+ className?: string;
11
+ children?: React.ReactNode;
12
+ } & Omit<React.ComponentPropsWithoutRef<T>, "as" | "value" | "className" | "style" | "children">;
13
+ /** A text role drawn from a `TextStyle`: its font, size, weight, spacing, alignment, case and tone, all from CSS variables. */
14
+ declare function StyledText<T extends React.ElementType = "p">({ as, value, className, children, ...rest }: StyledTextProps<T>): React.JSX.Element;
15
+
16
+ /** The curated families of `@krizaka/fonts`, by role: `display` (the headlines), `text` (reading), `mono` (the typewriter), `cahier` (the pen). */
17
+ declare const fontIds: readonly ["display", "text", "mono", "cahier"];
18
+ type FontId = (typeof fontIds)[number];
19
+ /** The steps of the type scale, smallest to largest. Never pixels. */
20
+ declare const sizeSteps: readonly ["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl"];
21
+ type SizeStep = (typeof sizeSteps)[number];
22
+ declare const textWeights: readonly [400, 500, 600, 700];
23
+ type TextWeight = (typeof textWeights)[number];
24
+ declare const leadings: readonly ["tight", "normal", "relaxed"];
25
+ type Leading = (typeof leadings)[number];
26
+ declare const trackings: readonly ["tight", "normal", "wide"];
27
+ type Tracking = (typeof trackings)[number];
28
+ declare const aligns: readonly ["start", "center", "end"];
29
+ type Align = (typeof aligns)[number];
30
+ declare const cases: readonly ["none", "upper", "small-caps"];
31
+ type Case = (typeof cases)[number];
32
+ /** The text roles of the tokens, and the brand hue. */
33
+ declare const toneIds: readonly ["primary", "secondary", "muted", "accent"];
34
+ type ToneId = (typeof toneIds)[number];
35
+ /** A text style: what a shop owner chooses, stored as it is. */
36
+ type TextStyle = {
37
+ font: FontId;
38
+ size: SizeStep;
39
+ weight: TextWeight;
40
+ leading: Leading;
41
+ tracking: Tracking;
42
+ align: Align;
43
+ case: Case;
44
+ italic: boolean;
45
+ tone: ToneId;
46
+ };
47
+ /** What `parseTextStyle` answers for anything that is not a text style. */
48
+ declare const defaultTextStyle: Readonly<TextStyle>;
49
+ /** The weights each face is cut in: a picker offers these, never a synthesised bold. */
50
+ declare const fontWeights: Readonly<Record<FontId, readonly TextWeight[]>>;
51
+ /**
52
+ * Validates what was stored (or sent): the text style, or `defaultTextStyle` for anything invalid — a free font name, a
53
+ * hex colour, a pixel size, CSS text, a value that is not an object. Keys a text style does not have are dropped; keys it
54
+ * lacks (a value stored before one was added) take their default. Usable on a server.
55
+ */
56
+ declare function parseTextStyle(input: unknown): TextStyle;
57
+ /** The `className` and `style` that draw a text style. Built from fixed tables of CSS variables only. */
58
+ declare function textStyleProps(style: unknown): {
59
+ className: string;
60
+ style: CSSProperties;
61
+ };
62
+
63
+ export { type Align, type Case, type FontId, type Leading, type SizeStep, StyledText, type StyledTextProps, type TextStyle, type TextWeight, type ToneId, type Tracking, aligns, cases, defaultTextStyle, fontIds, fontWeights, leadings, parseTextStyle, sizeSteps, textStyleProps, textWeights, toneIds, trackings };
@@ -0,0 +1,109 @@
1
+ // src/cx.ts
2
+ function cx(...parts) {
3
+ return parts.filter(Boolean).join(" ");
4
+ }
5
+
6
+ // src/text-style/text-style.ts
7
+ import * as z from "zod/mini";
8
+ var fontIds = ["display", "text", "mono", "cahier"];
9
+ var sizeSteps = ["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl"];
10
+ var textWeights = [400, 500, 600, 700];
11
+ var leadings = ["tight", "normal", "relaxed"];
12
+ var trackings = ["tight", "normal", "wide"];
13
+ var aligns = ["start", "center", "end"];
14
+ var cases = ["none", "upper", "small-caps"];
15
+ var toneIds = ["primary", "secondary", "muted", "accent"];
16
+ var defaultTextStyle = Object.freeze({
17
+ font: "text",
18
+ size: "md",
19
+ weight: 400,
20
+ leading: "normal",
21
+ tracking: "normal",
22
+ align: "start",
23
+ case: "none",
24
+ italic: false,
25
+ tone: "primary"
26
+ });
27
+ var fontWeights = {
28
+ display: [400],
29
+ text: [400, 600, 700],
30
+ mono: [400, 700],
31
+ cahier: [500]
32
+ };
33
+ var schema = z.object({
34
+ font: z.enum(fontIds),
35
+ size: z.enum(sizeSteps),
36
+ weight: z.union([z.literal(400), z.literal(500), z.literal(600), z.literal(700)]),
37
+ leading: z.enum(leadings),
38
+ tracking: z.enum(trackings),
39
+ align: z.enum(aligns),
40
+ case: z.enum(cases),
41
+ italic: z.boolean(),
42
+ tone: z.enum(toneIds)
43
+ });
44
+ function parseTextStyle(input) {
45
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return { ...defaultTextStyle };
46
+ const own = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== void 0));
47
+ const parsed = schema.safeParse({ ...defaultTextStyle, ...own });
48
+ return parsed.success ? { ...parsed.data } : { ...defaultTextStyle };
49
+ }
50
+ var rem = { xs: "0.75rem", sm: "0.875rem", md: "1rem", lg: "1.125rem", xl: "1.25rem", "2xl": "1.5rem", "3xl": "1.875rem", "4xl": "2.25rem" };
51
+ var lineHeight = { tight: "1.15", normal: "1.4", relaxed: "1.7" };
52
+ var letterSpacing = { tight: "-0.02em", normal: "0em", wide: "0.08em" };
53
+ var textAlign = { start: "start", center: "center", end: "end" };
54
+ var tone = {
55
+ primary: "var(--kz-text-primary)",
56
+ secondary: "var(--kz-text-secondary)",
57
+ muted: "var(--kz-text-muted)",
58
+ accent: "var(--kz-accent-text)"
59
+ };
60
+ var fontVariable = {
61
+ display: "var(--kz-font-display)",
62
+ text: "var(--kz-font-text)",
63
+ mono: "var(--kz-font-mono)",
64
+ cahier: "var(--kz-font-cahier)"
65
+ };
66
+ var sizeVariable = (step) => `var(--kz-text-style-${step}, ${rem[step]})`;
67
+ var toneVariable = (id) => tone[id];
68
+ function textStyleProps(style) {
69
+ const v = parseTextStyle(style);
70
+ return {
71
+ className: "kz-text-style",
72
+ style: {
73
+ fontFamily: fontVariable[v.font],
74
+ fontSize: sizeVariable(v.size),
75
+ fontWeight: v.weight,
76
+ lineHeight: `var(--kz-text-style-leading-${v.leading}, ${lineHeight[v.leading]})`,
77
+ letterSpacing: `var(--kz-text-style-tracking-${v.tracking}, ${letterSpacing[v.tracking]})`,
78
+ textAlign: textAlign[v.align],
79
+ textTransform: v.case === "upper" ? "uppercase" : "none",
80
+ fontVariantCaps: v.case === "small-caps" ? "small-caps" : "normal",
81
+ fontStyle: v.italic ? "italic" : "normal",
82
+ color: toneVariable(v.tone)
83
+ }
84
+ };
85
+ }
86
+
87
+ // src/text-style/styled-text.tsx
88
+ import { jsx } from "react/jsx-runtime";
89
+ function StyledText({ as, value, className, children, ...rest }) {
90
+ const Tag = as ?? "p";
91
+ const props = textStyleProps(value);
92
+ return /* @__PURE__ */ jsx(Tag, { ...rest, className: cx(props.className, className), style: props.style, children });
93
+ }
94
+ export {
95
+ StyledText,
96
+ aligns,
97
+ cases,
98
+ defaultTextStyle,
99
+ fontIds,
100
+ fontWeights,
101
+ leadings,
102
+ parseTextStyle,
103
+ sizeSteps,
104
+ textStyleProps,
105
+ textWeights,
106
+ toneIds,
107
+ trackings
108
+ };
109
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cx.ts","../../src/text-style/text-style.ts","../../src/text-style/styled-text.tsx"],"sourcesContent":["/** Joins class names, skipping the falsy ones. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n","// Server-safe (no hook, no React): the value of a text style, its validation and its CSS. A shop owner's choice is stored\n// by the app, so the value is plain data and its CSS is built from fixed tables of CSS variables — what comes from a\n// database never reaches a style sheet as text. The fonts are the curated roles of @krizaka/fonts (the product theme\n// says which family a role is), the sizes are the type scale's steps, the tones are the text roles and the brand hue.\nimport type { CSSProperties } from \"react\";\nimport * as z from \"zod/mini\";\n\n/** The curated families of `@krizaka/fonts`, by role: `display` (the headlines), `text` (reading), `mono` (the typewriter), `cahier` (the pen). */\nexport const fontIds = [\"display\", \"text\", \"mono\", \"cahier\"] as const;\nexport type FontId = (typeof fontIds)[number];\n\n/** The steps of the type scale, smallest to largest. Never pixels. */\nexport const sizeSteps = [\"xs\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\", \"3xl\", \"4xl\"] as const;\nexport type SizeStep = (typeof sizeSteps)[number];\n\nexport const textWeights = [400, 500, 600, 700] as const;\nexport type TextWeight = (typeof textWeights)[number];\n\nexport const leadings = [\"tight\", \"normal\", \"relaxed\"] as const;\nexport type Leading = (typeof leadings)[number];\n\nexport const trackings = [\"tight\", \"normal\", \"wide\"] as const;\nexport type Tracking = (typeof trackings)[number];\n\nexport const aligns = [\"start\", \"center\", \"end\"] as const;\nexport type Align = (typeof aligns)[number];\n\nexport const cases = [\"none\", \"upper\", \"small-caps\"] as const;\nexport type Case = (typeof cases)[number];\n\n/** The text roles of the tokens, and the brand hue. */\nexport const toneIds = [\"primary\", \"secondary\", \"muted\", \"accent\"] as const;\nexport type ToneId = (typeof toneIds)[number];\n\n/** A text style: what a shop owner chooses, stored as it is. */\nexport type TextStyle = {\n font: FontId;\n size: SizeStep;\n weight: TextWeight;\n leading: Leading;\n tracking: Tracking;\n align: Align;\n case: Case;\n italic: boolean;\n tone: ToneId;\n};\n\n/** What `parseTextStyle` answers for anything that is not a text style. */\nexport const defaultTextStyle: Readonly<TextStyle> = Object.freeze({\n font: \"text\",\n size: \"md\",\n weight: 400,\n leading: \"normal\",\n tracking: \"normal\",\n align: \"start\",\n case: \"none\",\n italic: false,\n tone: \"primary\",\n});\n\n/** The weights each face is cut in: a picker offers these, never a synthesised bold. */\nexport const fontWeights: Readonly<Record<FontId, readonly TextWeight[]>> = {\n display: [400],\n text: [400, 600, 700],\n mono: [400, 700],\n cahier: [500],\n};\n\nconst schema = z.object({\n font: z.enum(fontIds),\n size: z.enum(sizeSteps),\n weight: z.union([z.literal(400), z.literal(500), z.literal(600), z.literal(700)]),\n leading: z.enum(leadings),\n tracking: z.enum(trackings),\n align: z.enum(aligns),\n case: z.enum(cases),\n italic: z.boolean(),\n tone: z.enum(toneIds),\n});\n\n/**\n * Validates what was stored (or sent): the text style, or `defaultTextStyle` for anything invalid — a free font name, a\n * hex colour, a pixel size, CSS text, a value that is not an object. Keys a text style does not have are dropped; keys it\n * lacks (a value stored before one was added) take their default. Usable on a server.\n */\nexport function parseTextStyle(input: unknown): TextStyle {\n if (typeof input !== \"object\" || input === null || Array.isArray(input)) return { ...defaultTextStyle };\n const own = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined));\n const parsed = schema.safeParse({ ...defaultTextStyle, ...own });\n return parsed.success ? { ...parsed.data } : { ...defaultTextStyle };\n}\n\nconst rem: Record<SizeStep, string> = { xs: \"0.75rem\", sm: \"0.875rem\", md: \"1rem\", lg: \"1.125rem\", xl: \"1.25rem\", \"2xl\": \"1.5rem\", \"3xl\": \"1.875rem\", \"4xl\": \"2.25rem\" };\nconst lineHeight: Record<Leading, string> = { tight: \"1.15\", normal: \"1.4\", relaxed: \"1.7\" };\nconst letterSpacing: Record<Tracking, string> = { tight: \"-0.02em\", normal: \"0em\", wide: \"0.08em\" };\nconst textAlign: Record<Align, CSSProperties[\"textAlign\"]> = { start: \"start\", center: \"center\", end: \"end\" };\nconst tone: Record<ToneId, string> = {\n primary: \"var(--kz-text-primary)\",\n secondary: \"var(--kz-text-secondary)\",\n muted: \"var(--kz-text-muted)\",\n accent: \"var(--kz-accent-text)\",\n};\n\n/** The CSS variable of a text role: the product theme's face for `display`, the preset's for the others. */\nexport const fontVariable: Readonly<Record<FontId, string>> = {\n display: \"var(--kz-font-display)\",\n text: \"var(--kz-font-text)\",\n mono: \"var(--kz-font-mono)\",\n cahier: \"var(--kz-font-cahier)\",\n};\n\n/** A step's size as a CSS value: `var(--kz-text-style-<step>, <rem>)` — a product may re-cut the scale with the variable. */\nexport const sizeVariable = (step: SizeStep): string => `var(--kz-text-style-${step}, ${rem[step]})`;\n\n/** A tone's colour as a CSS value: a role of the tokens. */\nexport const toneVariable = (id: ToneId): string => tone[id];\n\n/** The `className` and `style` that draw a text style. Built from fixed tables of CSS variables only. */\nexport function textStyleProps(style: unknown): { className: string; style: CSSProperties } {\n const v = parseTextStyle(style);\n return {\n className: \"kz-text-style\",\n style: {\n fontFamily: fontVariable[v.font],\n fontSize: sizeVariable(v.size),\n fontWeight: v.weight,\n lineHeight: `var(--kz-text-style-leading-${v.leading}, ${lineHeight[v.leading]})`,\n letterSpacing: `var(--kz-text-style-tracking-${v.tracking}, ${letterSpacing[v.tracking]})`,\n textAlign: textAlign[v.align],\n textTransform: v.case === \"upper\" ? \"uppercase\" : \"none\",\n fontVariantCaps: v.case === \"small-caps\" ? \"small-caps\" : \"normal\",\n fontStyle: v.italic ? \"italic\" : \"normal\",\n color: toneVariable(v.tone),\n },\n };\n}\n\n/** A colour read from the page, as `[r, g, b]` in 0–255, or `null` when it cannot be read (the check then says nothing). */\nexport function parseColor(text: string): [number, number, number] | null {\n const value = text.trim().toLowerCase();\n const hex = /^#([0-9a-f]{3,8})$/.exec(value)?.[1];\n if (hex && [3, 4, 6, 8].includes(hex.length)) {\n const full = hex.length <= 4 ? [...hex].map((c) => c + c).join(\"\") : hex;\n return [0, 2, 4].map((i) => Number.parseInt(full.slice(i, i + 2), 16)) as [number, number, number];\n }\n const rgb = /^rgba?\\(([^)]+)\\)$/.exec(value)?.[1];\n if (rgb) {\n const parts = rgb.split(/[\\s,/]+/).filter(Boolean).slice(0, 3).map((p) => (p.endsWith(\"%\") ? (Number.parseFloat(p) / 100) * 255 : Number.parseFloat(p)));\n return parts.length === 3 && parts.every(Number.isFinite) ? (parts as [number, number, number]) : null;\n }\n const srgb = /^color\\(srgb\\s+([^)]+)\\)$/.exec(value)?.[1];\n if (srgb) {\n const parts = srgb.split(/[\\s/]+/).filter(Boolean).slice(0, 3).map((p) => Number.parseFloat(p) * 255);\n return parts.length === 3 && parts.every(Number.isFinite) ? (parts as [number, number, number]) : null;\n }\n return null;\n}\n\nconst channel = (c: number) => {\n const s = Math.min(Math.max(c, 0), 255) / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n};\nconst luminance = ([r, g, b]: [number, number, number]) => 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);\n\n/** The WCAG contrast ratio of two colours (1 – 21). */\nexport function contrastRatio(foreground: [number, number, number], background: [number, number, number]): number {\n const a = luminance(foreground);\n const b = luminance(background);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n}\n\n/** The ratio WCAG asks of large text. */\nexport const largeTextRatio = 3;\n/** The ratio WCAG asks of body text. */\nexport const bodyTextRatio = 4.5;\n\n/** Large text for WCAG: 24 px and over, or bold from 18.66 px (`xl`, 20 px, in bold). */\nexport function isLargeText(style: Pick<TextStyle, \"size\" | \"weight\">): boolean {\n const at = sizeSteps.indexOf(style.size);\n return at >= sizeSteps.indexOf(\"2xl\") || (at >= sizeSteps.indexOf(\"xl\") && style.weight >= 700);\n}\n\n/** The ratio a style's text must reach on its surface. */\nexport const requiredContrast = (style: Pick<TextStyle, \"size\" | \"weight\">): number => (isLargeText(style) ? largeTextRatio : bodyTextRatio);\n\n/** True when body text in this step is under the minimum: a warning to show, never a size to force. */\nexport const isUnderMinimumSize = (size: SizeStep, minimum: SizeStep): boolean => sizeSteps.indexOf(size) < sizeSteps.indexOf(minimum);\n","// Server-safe: a text drawn with a stored text style. Whatever is passed as `value` goes through `parseTextStyle`.\nimport * as React from \"react\";\n\nimport { cx } from \"../cx\";\nimport { textStyleProps } from \"./text-style\";\n\nexport type StyledTextProps<T extends React.ElementType = \"p\"> = {\n /** The element drawn: `h1`…`h6`, `p`, `span`, `div`. */\n as?: T;\n /** The stored text style — validated here: anything invalid draws the default. */\n value?: unknown;\n /** Merged after the style's own class. */\n className?: string;\n children?: React.ReactNode;\n} & Omit<React.ComponentPropsWithoutRef<T>, \"as\" | \"value\" | \"className\" | \"style\" | \"children\">;\n\n/** A text role drawn from a `TextStyle`: its font, size, weight, spacing, alignment, case and tone, all from CSS variables. */\nexport function StyledText<T extends React.ElementType = \"p\">({ as, value, className, children, ...rest }: StyledTextProps<T>) {\n const Tag: React.ElementType = as ?? \"p\";\n const props = textStyleProps(value);\n return (\n <Tag {...rest} className={cx(props.className, className)} style={props.style}>\n {children}\n </Tag>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,149 @@
1
+ import * as React from 'react';
2
+ import { CSSProperties } from 'react';
3
+
4
+ type StyledTextProps<T extends React.ElementType = "p"> = {
5
+ /** The element drawn: `h1`…`h6`, `p`, `span`, `div`. */
6
+ as?: T;
7
+ /** The stored text style — validated here: anything invalid draws the default. */
8
+ value?: unknown;
9
+ /** Merged after the style's own class. */
10
+ className?: string;
11
+ children?: React.ReactNode;
12
+ } & Omit<React.ComponentPropsWithoutRef<T>, "as" | "value" | "className" | "style" | "children">;
13
+ /** A text role drawn from a `TextStyle`: its font, size, weight, spacing, alignment, case and tone, all from CSS variables. */
14
+ declare function StyledText<T extends React.ElementType = "p">({ as, value, className, children, ...rest }: StyledTextProps<T>): React.JSX.Element;
15
+
16
+ /** The curated families of `@krizaka/fonts`, by role: `display` (the headlines), `text` (reading), `mono` (the typewriter), `cahier` (the pen). */
17
+ declare const fontIds: readonly ["display", "text", "mono", "cahier"];
18
+ type FontId = (typeof fontIds)[number];
19
+ /** The steps of the type scale, smallest to largest. Never pixels. */
20
+ declare const sizeSteps: readonly ["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl"];
21
+ type SizeStep = (typeof sizeSteps)[number];
22
+ declare const textWeights: readonly [400, 500, 600, 700];
23
+ type TextWeight = (typeof textWeights)[number];
24
+ declare const leadings: readonly ["tight", "normal", "relaxed"];
25
+ type Leading = (typeof leadings)[number];
26
+ declare const trackings: readonly ["tight", "normal", "wide"];
27
+ type Tracking = (typeof trackings)[number];
28
+ declare const aligns: readonly ["start", "center", "end"];
29
+ type Align = (typeof aligns)[number];
30
+ declare const cases: readonly ["none", "upper", "small-caps"];
31
+ type Case = (typeof cases)[number];
32
+ /** The text roles of the tokens, and the brand hue. */
33
+ declare const toneIds: readonly ["primary", "secondary", "muted", "accent"];
34
+ type ToneId = (typeof toneIds)[number];
35
+ /** A text style: what a shop owner chooses, stored as it is. */
36
+ type TextStyle = {
37
+ font: FontId;
38
+ size: SizeStep;
39
+ weight: TextWeight;
40
+ leading: Leading;
41
+ tracking: Tracking;
42
+ align: Align;
43
+ case: Case;
44
+ italic: boolean;
45
+ tone: ToneId;
46
+ };
47
+ /** What `parseTextStyle` answers for anything that is not a text style. */
48
+ declare const defaultTextStyle: Readonly<TextStyle>;
49
+ /** The weights each face is cut in: a picker offers these, never a synthesised bold. */
50
+ declare const fontWeights: Readonly<Record<FontId, readonly TextWeight[]>>;
51
+ /**
52
+ * Validates what was stored (or sent): the text style, or `defaultTextStyle` for anything invalid — a free font name, a
53
+ * hex colour, a pixel size, CSS text, a value that is not an object. Keys a text style does not have are dropped; keys it
54
+ * lacks (a value stored before one was added) take their default. Usable on a server.
55
+ */
56
+ declare function parseTextStyle(input: unknown): TextStyle;
57
+ /** The `className` and `style` that draw a text style. Built from fixed tables of CSS variables only. */
58
+ declare function textStyleProps(style: unknown): {
59
+ className: string;
60
+ style: CSSProperties;
61
+ };
62
+ /** A colour read from the page, as `[r, g, b]` in 0–255, or `null` when it cannot be read (the check then says nothing). */
63
+ declare function parseColor(text: string): [number, number, number] | null;
64
+ /** The WCAG contrast ratio of two colours (1 – 21). */
65
+ declare function contrastRatio(foreground: [number, number, number], background: [number, number, number]): number;
66
+ /** The ratio WCAG asks of large text. */
67
+ declare const largeTextRatio = 3;
68
+ /** The ratio WCAG asks of body text. */
69
+ declare const bodyTextRatio = 4.5;
70
+ /** Large text for WCAG: 24 px and over, or bold from 18.66 px (`xl`, 20 px, in bold). */
71
+ declare function isLargeText(style: Pick<TextStyle, "size" | "weight">): boolean;
72
+ /** The ratio a style's text must reach on its surface. */
73
+ declare const requiredContrast: (style: Pick<TextStyle, "size" | "weight">) => number;
74
+
75
+ /** The controls of the picker, in the order they are drawn. */
76
+ declare const textStyleFields: readonly ["font", "size", "weight", "leading", "tracking", "align", "case", "italic", "tone"];
77
+ type TextStyleField = (typeof textStyleFields)[number];
78
+ type TextStyleLabels = {
79
+ /** The name of the whole control. */
80
+ picker: string;
81
+ font: string;
82
+ size: string;
83
+ weight: string;
84
+ leading: string;
85
+ tracking: string;
86
+ align: string;
87
+ case: string;
88
+ italic: string;
89
+ tone: string;
90
+ presets: string;
91
+ preview: string;
92
+ fonts: Record<FontId, string>;
93
+ weights: Record<TextWeight, string>;
94
+ leadings: Record<Leading, string>;
95
+ trackings: Record<Tracking, string>;
96
+ aligns: Record<Align, string>;
97
+ cases: Record<Case, string>;
98
+ tones: Record<ToneId, string>;
99
+ /** The contrast warning: `{ratio}` is what the tone reaches, `{min}` what it must. */
100
+ contrastWarning: string;
101
+ /** The small-text warning: `{size}` is the smallest step advised for body text. */
102
+ minSizeWarning: string;
103
+ };
104
+ /** The English words. */
105
+ declare const textStyleLabels: TextStyleLabels;
106
+ /** The French words. */
107
+ declare const textStyleLabelsFr: TextStyleLabels;
108
+ type TextStylePreset = {
109
+ /** A stable key. */
110
+ id: string;
111
+ /** The name on the button, passed translated (« Titre », « Prix »…). */
112
+ label: string;
113
+ /** The style it applies; what it does not say takes the default. Validated when applied. */
114
+ value: Partial<TextStyle>;
115
+ };
116
+ type TextStylePickerProps = {
117
+ /** The text style, controlled. Validated by `parseTextStyle`: anything invalid shows the default. */
118
+ value: TextStyle;
119
+ /** Called with the whole new text style at each change. */
120
+ onChange: (value: TextStyle) => void;
121
+ /** The sample the preview shows, passed translated ("Boulangerie Martin"). */
122
+ previewText: string;
123
+ /** Styles the person can start from, as data. */
124
+ presets?: readonly TextStylePreset[];
125
+ /** The controls to show, in the order of `textStyleFields` (just `["font", "size"]`). A preset then changes only these. */
126
+ fields?: readonly TextStyleField[];
127
+ /** A denser form for a popover from a toolbar. */
128
+ compact?: boolean;
129
+ /** The words, passed translated: `textStyleLabels` (EN) or `textStyleLabelsFr`, or the host's own. */
130
+ labels?: Partial<TextStyleLabels>;
131
+ /** The colour the text will sit on, for the preview and the contrast check (a CSS colour). By default the page's own surface. */
132
+ surface?: string;
133
+ /**
134
+ * What the text is for: `body` (reading text, which `minBodySize` guards) or `title` (a heading, which may be small).
135
+ * @default "body"
136
+ */
137
+ role?: "body" | "title";
138
+ /**
139
+ * The smallest step advised for body text: under it, a warning shows — the size is never forced.
140
+ * @default "sm"
141
+ */
142
+ minBodySize?: SizeStep;
143
+ /** Merged last on the root. */
144
+ className?: string;
145
+ };
146
+ /** The control of a text style: font, size, weight, spacing, alignment, case, italic and tone, with a live preview. */
147
+ declare function TextStylePicker({ value, onChange, previewText, presets, fields, compact, labels: given, surface, role, minBodySize, className, }: TextStylePickerProps): React.JSX.Element;
148
+
149
+ export { type Align, type Case, type FontId, type Leading, type SizeStep, StyledText, type StyledTextProps, type TextStyle, type TextStyleField, type TextStyleLabels, TextStylePicker, type TextStylePickerProps, type TextStylePreset, type TextWeight, type ToneId, type Tracking, aligns, bodyTextRatio, cases, contrastRatio, defaultTextStyle, fontIds, fontWeights, isLargeText, largeTextRatio, leadings, parseColor, parseTextStyle, requiredContrast, sizeSteps, textStyleFields, textStyleLabels, textStyleLabelsFr, textStyleProps, textWeights, toneIds, trackings };