@stonedogcode/style 0.9.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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +18 -0
  3. package/README.md +699 -0
  4. package/package.json +95 -0
  5. package/src/components/DictationControls.tsx +141 -0
  6. package/src/components/DictationPrompt.tsx +78 -0
  7. package/src/components/StyledBox.tsx +174 -0
  8. package/src/components/StyledButton.tsx +144 -0
  9. package/src/components/StyledCollapsible.tsx +127 -0
  10. package/src/components/StyledDefinitionList.tsx +134 -0
  11. package/src/components/StyledFieldset.tsx +157 -0
  12. package/src/components/StyledFlex.tsx +13 -0
  13. package/src/components/StyledFooter.tsx +399 -0
  14. package/src/components/StyledFormLabel.tsx +141 -0
  15. package/src/components/StyledGrid.tsx +109 -0
  16. package/src/components/StyledGridItem.tsx +19 -0
  17. package/src/components/StyledHStack.tsx +145 -0
  18. package/src/components/StyledHeading.tsx +79 -0
  19. package/src/components/StyledHrRule.tsx +33 -0
  20. package/src/components/StyledIcon.tsx +172 -0
  21. package/src/components/StyledIconButton.tsx +135 -0
  22. package/src/components/StyledInputBool.tsx +81 -0
  23. package/src/components/StyledInputRadio.tsx +141 -0
  24. package/src/components/StyledInputSelect.tsx +115 -0
  25. package/src/components/StyledInputSlider.tsx +83 -0
  26. package/src/components/StyledInputText.tsx +146 -0
  27. package/src/components/StyledInputTextArea.tsx +119 -0
  28. package/src/components/StyledInputToggle.tsx +224 -0
  29. package/src/components/StyledList.tsx +188 -0
  30. package/src/components/StyledScrollbar.tsx +53 -0
  31. package/src/components/StyledSearch.tsx +78 -0
  32. package/src/components/StyledSeparator.tsx +38 -0
  33. package/src/components/StyledSidebar.tsx +555 -0
  34. package/src/components/StyledSimpleGrid.tsx +99 -0
  35. package/src/components/StyledSparkLine.tsx +119 -0
  36. package/src/components/StyledSpinner.tsx +91 -0
  37. package/src/components/StyledStack.tsx +62 -0
  38. package/src/components/StyledText.tsx +99 -0
  39. package/src/components/StyledTooltip.tsx +398 -0
  40. package/src/components/StyledVStack.tsx +143 -0
  41. package/src/components/TitleLogo.tsx +223 -0
  42. package/src/components/create-icon.tsx +66 -0
  43. package/src/components/create-intent-button.tsx +134 -0
  44. package/src/components/dictation.ts +71 -0
  45. package/src/components/intent-buttons.ts +154 -0
  46. package/src/config/can-hover.ts +75 -0
  47. package/src/config/density.ts +138 -0
  48. package/src/config/font-size.ts +113 -0
  49. package/src/config/intent-icons.tsx +116 -0
  50. package/src/config/logger.ts +60 -0
  51. package/src/config/style-config.tsx +263 -0
  52. package/src/config/types.ts +137 -0
  53. package/src/index.ts +259 -0
  54. package/src/preset/index.ts +243 -0
  55. package/src/preset/recipes/arrows.ts +29 -0
  56. package/src/preset/recipes/box.ts +122 -0
  57. package/src/preset/recipes/button.ts +161 -0
  58. package/src/preset/recipes/dl-list.ts +109 -0
  59. package/src/preset/recipes/drawer.ts +125 -0
  60. package/src/preset/recipes/form.ts +95 -0
  61. package/src/preset/recipes/icon-button.ts +161 -0
  62. package/src/preset/recipes/icon.ts +34 -0
  63. package/src/preset/recipes/input-bool.ts +184 -0
  64. package/src/preset/recipes/input-dropdown.ts +93 -0
  65. package/src/preset/recipes/input-radio.ts +158 -0
  66. package/src/preset/recipes/input-surface.ts +152 -0
  67. package/src/preset/recipes/input-text.ts +17 -0
  68. package/src/preset/recipes/list.ts +196 -0
  69. package/src/preset/recipes/menu.ts +28 -0
  70. package/src/preset/recipes/separator.ts +89 -0
  71. package/src/preset/recipes/stack.ts +89 -0
  72. package/src/preset/recipes/striped.ts +34 -0
  73. package/src/preset/recipes/text.ts +41 -0
  74. package/src/preset/recipes/tooltip.ts +77 -0
  75. package/src/preset/semantic-variables.ts +283 -0
@@ -0,0 +1,263 @@
1
+ "use client";
2
+
3
+ import React, { createContext, useContext, useMemo } from "react";
4
+ import type { DensityProfile, FontSizeProfile, IconSize, ThemeVariant } from "./types";
5
+ import { resolveDensityStep, type DensityBase, type DensityStep } from "./density";
6
+ import { THEME_VARIANTS } from "./types";
7
+ import { IntentIconProvider, type IntentIcons } from "./intent-icons";
8
+
9
+ /**
10
+ * Everything this component library needs to know about the host application.
11
+ *
12
+ * The components were extracted from an app where they read a 461-line Zustand
13
+ * store holding auth, widgets, notes, services and config together. Depending on
14
+ * that store is what made them unshareable, so the seam was drawn at the
15
+ * narrowest possible place: **these two settings are all the styling actually
16
+ * needs.** Anything a component wants beyond them belongs in a prop.
17
+ *
18
+ * Keeping this interface small is a load-bearing constraint, not tidiness. Every
19
+ * field added here is a field a second host must supply before it can render a
20
+ * single button.
21
+ */
22
+ export interface StyleConfig {
23
+ /**
24
+ * The user's app-wide text size. Drives `StyledText`, and through it nearly
25
+ * all visible text.
26
+ */
27
+ fontSizeProfile: FontSizeProfile;
28
+
29
+ /**
30
+ * The user's app-wide appearance. A component may override it per call site;
31
+ * see `useResolvedVariant` for the precedence rule.
32
+ */
33
+ variant: ThemeVariant;
34
+
35
+ /**
36
+ * The **user's** density preference, relative to the app's baseline.
37
+ *
38
+ * Not cosmetic: at `compact` the intent buttons drop their text label and
39
+ * show only their icon, so this changes what a control *says*, not just its
40
+ * padding. That is why it lives here rather than being left to CSS.
41
+ */
42
+ density: DensityProfile;
43
+
44
+ /**
45
+ * The **application's** density baseline — the rung `density: "normal"` means.
46
+ *
47
+ * HopperGuard runs `spacious`, both Optima products `compact`, RozCards
48
+ * `standard`. See `config/density.ts`: this and `density` are a position and
49
+ * an offset on one scale, not two competing axes.
50
+ *
51
+ * Defaults to `standard`, whose spacing (8px) is exactly the fallback the
52
+ * recipes have always used — so a host that says nothing sees no change.
53
+ */
54
+ densityBase: DensityBase;
55
+
56
+ /**
57
+ * The app-wide default icon size, used by any `StyledIcon` that is not given
58
+ * an explicit `size`.
59
+ *
60
+ * This exists because the alternative is naming a size at every call site,
61
+ * which is how an application ends up with three icon scales and no way to
62
+ * retune any of them. Font size is already host-tunable — every `fontSizeMap`
63
+ * entry is a `var(--font-sizes-*)` reference the host can define — and this is
64
+ * the equivalent seam for icons.
65
+ *
66
+ * The default stays `"2x"`: HopperGuard serves an often-elderly, sometimes
67
+ * cognitively-impaired audience and runs deliberately large, and ~150 of its
68
+ * call sites rely on that default. A host wanting a conventional web scale
69
+ * (a business tool for a general audience) sets `"md"`.
70
+ */
71
+ iconSize: IconSize;
72
+ }
73
+
74
+ /**
75
+ * What a host that supplies nothing gets.
76
+ *
77
+ * Both values are deliberately the middle/safest option rather than the
78
+ * smallest or the flashiest: an unconfigured app should be readable and plain,
79
+ * so that forgetting the provider degrades to "looks unstyled" rather than
80
+ * "unreadable at 0.75rem".
81
+ */
82
+ export const DEFAULT_STYLE_CONFIG: StyleConfig = {
83
+ fontSizeProfile: "md",
84
+ variant: "solid",
85
+ density: "normal",
86
+ // `standard` + `normal` resolves to 8px, which is the fallback baked into
87
+ // every recipe. An unconfigured host renders exactly as it did before the
88
+ // ladder existed.
89
+ densityBase: "standard",
90
+ // Not the middle of the scale, unlike the two above: this one is pinned to
91
+ // what the originating application already renders. Changing it would be an
92
+ // invisible, app-wide visual change to every existing consumer.
93
+ iconSize: "2x",
94
+ };
95
+
96
+ const StyleConfigContext = createContext<StyleConfig>(DEFAULT_STYLE_CONFIG);
97
+
98
+ /**
99
+ * Every setting optional, and explicitly accepting `undefined`.
100
+ *
101
+ * `Partial<StyleConfig>` alone is not enough under
102
+ * `exactOptionalPropertyTypes`: it makes each key optional but still refuses an
103
+ * explicit `undefined`. Hosts routinely pass one — `variant={user?.variant}` —
104
+ * and rejecting that would push a conditional spread into every call site for
105
+ * no benefit, since the provider already treats absent and undefined the same.
106
+ */
107
+ type OptionalStyleConfig = {
108
+ [K in keyof StyleConfig]?: StyleConfig[K] | undefined;
109
+ };
110
+
111
+ export interface StonedogStyleProviderProps extends OptionalStyleConfig {
112
+ children: React.ReactNode;
113
+ /**
114
+ * Which icon to draw for each intent — see `config/intent-icons.tsx`.
115
+ *
116
+ * This is how one `StyledDeleteButton` serves a Font Awesome product and a
117
+ * Lucide one. Optional: an unregistered intent simply renders no icon.
118
+ */
119
+ icons?: IntentIcons | undefined;
120
+ }
121
+
122
+ /**
123
+ * Supplies the styling settings to everything beneath it.
124
+ *
125
+ * Wrap the app once, near the root, and feed it from wherever the host keeps
126
+ * user preferences. HopperGuard renders it inside its existing config provider
127
+ * and passes the two values through from the Zustand store; a host with no such
128
+ * store can pass literals, or omit the provider entirely and take the defaults.
129
+ *
130
+ * ```tsx
131
+ * <StonedogStyleProvider fontSizeProfile={profile} variant={variant}>
132
+ * <App />
133
+ * </StonedogStyleProvider>
134
+ * ```
135
+ *
136
+ * Props are merged over the defaults individually, so a host that only cares
137
+ * about font size does not have to name a variant it has no opinion on.
138
+ */
139
+ export function StonedogStyleProvider({
140
+ children,
141
+ fontSizeProfile,
142
+ variant,
143
+ iconSize,
144
+ density,
145
+ densityBase,
146
+ icons,
147
+ }: StonedogStyleProviderProps) {
148
+ const value = useMemo<StyleConfig>(
149
+ () => ({
150
+ fontSizeProfile:
151
+ fontSizeProfile ?? DEFAULT_STYLE_CONFIG.fontSizeProfile,
152
+ variant: variant ?? DEFAULT_STYLE_CONFIG.variant,
153
+ iconSize: iconSize ?? DEFAULT_STYLE_CONFIG.iconSize,
154
+ density: density ?? DEFAULT_STYLE_CONFIG.density,
155
+ densityBase: densityBase ?? DEFAULT_STYLE_CONFIG.densityBase,
156
+ }),
157
+ [fontSizeProfile, variant, iconSize, density, densityBase],
158
+ );
159
+
160
+ return (
161
+ <StyleConfigContext.Provider value={value}>
162
+ {/*
163
+ The icon registry rides along with the style config so a host wires up
164
+ one provider, not two — and so the intent buttons cannot end up inside
165
+ a styled tree with no icons registered.
166
+ */}
167
+ <IntentIconProvider icons={icons ?? {}}>{children}</IntentIconProvider>
168
+ </StyleConfigContext.Provider>
169
+ );
170
+ }
171
+
172
+ /**
173
+ * @deprecated Renamed to `StonedogStyleProvider` (NEH-251).
174
+ *
175
+ * Kept so each consumer can bump its submodule pointer on its own schedule
176
+ * rather than every repo moving in one lockstep sweep. Removed once HopperGuard,
177
+ * optima-filings and optima-cloud-saas have all landed their consumer PRs.
178
+ */
179
+ export const HopperStyleProvider = StonedogStyleProvider;
180
+
181
+ /** @deprecated Renamed to `StonedogStyleProviderProps` (NEH-251). */
182
+ export type HopperStyleProviderProps = StonedogStyleProviderProps;
183
+
184
+ /** The current styling settings. Safe outside a provider — returns defaults. */
185
+ export function useStyleConfig(): StyleConfig {
186
+ return useContext(StyleConfigContext);
187
+ }
188
+
189
+ /** The user's app-wide font-size profile. */
190
+ export function useFontSizeProfile(): FontSizeProfile {
191
+ return useStyleConfig().fontSizeProfile;
192
+ }
193
+
194
+ /** The app-wide default icon size. `StyledIcon` uses it when given no `size`. */
195
+ export function useIconSize(): IconSize {
196
+ return useStyleConfig().iconSize;
197
+ }
198
+
199
+ /**
200
+ * Resolve a control's appearance: **the caller's, else the user's app-wide
201
+ * setting, else `solid`.**
202
+ *
203
+ * This is three lines, which is exactly why it is shared. In the originating
204
+ * codebase each control picked its own default — a checkbox hard-coded `solid`,
205
+ * a wheel picker defaulted to `outline`, a phone field to `solid` — each
206
+ * plausible alone, and together they produced a form whose checkbox, phone
207
+ * field and wheel ignored the theme every other control followed.
208
+ *
209
+ * The narrowing matters as much as the fallback: a caller may pass a variant the
210
+ * theme recipes have no case for (`ghost`, `link`, or a value read from storage
211
+ * written by an older release). Coercing to `solid` renders a plain control;
212
+ * passing it through renders an *unstyled* one, because a recipe silently emits
213
+ * nothing for a variant it does not define.
214
+ *
215
+ * ## Pass `allowed` when your recipe defines more than the theme five
216
+ *
217
+ * The default list is the five appearances a user can select app-wide, and for
218
+ * most controls that is the right gate. But some recipes define extras that are
219
+ * reachable per-call-site and not offerable globally — `inputBoolRecipe` has
220
+ * `ghost` and `none`. Narrowing those to `solid` is silent: the control renders,
221
+ * it just quietly ignores what the call site asked for.
222
+ *
223
+ * That is not hypothetical. Migrating `StyledInputBool` into this package with
224
+ * the default list dropped `variant="ghost"` on the floor, and nothing failed
225
+ * except one test in the consuming app that happened to assert it.
226
+ *
227
+ * `allowed` must contain `"solid"`, since that is the fallback.
228
+ */
229
+ export function useResolvedVariant(variant?: string): ThemeVariant;
230
+ export function useResolvedVariant<T extends string>(
231
+ variant: string | undefined,
232
+ allowed: readonly T[],
233
+ ): T;
234
+ export function useResolvedVariant(
235
+ variant?: string,
236
+ allowed: readonly string[] = THEME_VARIANTS,
237
+ ): string {
238
+ const globalVariant = useStyleConfig().variant;
239
+ const candidate = variant ?? globalVariant;
240
+ return allowed.includes(candidate) ? candidate : "solid";
241
+ }
242
+
243
+ /**
244
+ * The user's density preference, as they chose it.
245
+ *
246
+ * Relative to the app's baseline, so it answers "did the user ask for tighter?"
247
+ * rather than "how much padding is there?". `useDensityStep` answers the
248
+ * second. `compact` is what makes intent buttons icon-only.
249
+ */
250
+ export function useDensity(): DensityProfile {
251
+ return useStyleConfig().density;
252
+ }
253
+
254
+ /**
255
+ * Where the app's baseline and the user's preference actually land.
256
+ *
257
+ * This is the value that maps to real spacing — feed it to
258
+ * `densityCustomProperties` to get the properties the recipes read.
259
+ */
260
+ export function useDensityStep(): DensityStep {
261
+ const { densityBase, density } = useStyleConfig();
262
+ return resolveDensityStep(densityBase, density);
263
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * The vocabulary shared by the recipes and the components.
3
+ *
4
+ * Ported from HopperGuard's `hopper-types` so this package depends on nothing
5
+ * private. The tuples are the source of truth — the unions derive from them, so
6
+ * a value can be validated at runtime and narrowed at compile time from one
7
+ * declaration.
8
+ */
9
+
10
+ /**
11
+ * The five appearances a user can choose app-wide. Every recipe defines all
12
+ * five, which is why `staticCss` force-generates them (see the preset).
13
+ */
14
+ export const THEME_VARIANTS = [
15
+ "solid",
16
+ "outline",
17
+ "aurora",
18
+ "glass",
19
+ "matte",
20
+ ] as const;
21
+
22
+ /**
23
+ * Appearances a *call site* can ask for but a user cannot select globally —
24
+ * a `ghost` toolbar button stays ghost whatever the app-wide variant is.
25
+ */
26
+ export const STYLE_VARIANTS = [
27
+ "ghost",
28
+ "none",
29
+ "link",
30
+ "unstyled",
31
+ "selected",
32
+ ] as const;
33
+
34
+ /** Semantic text treatments. Not appearances — meanings. */
35
+ export const TEXT_VARIANTS = ["unstyled", "error", "pop", "warning"] as const;
36
+
37
+ export const ALL_VARIANTS = [...THEME_VARIANTS, ...STYLE_VARIANTS] as const;
38
+
39
+ export type ThemeVariant = (typeof THEME_VARIANTS)[number];
40
+ export type StyleVariant = (typeof STYLE_VARIANTS)[number];
41
+ export type AllowedTextVariant = (typeof TEXT_VARIANTS)[number];
42
+ export type AllowedVariant = (typeof ALL_VARIANTS)[number];
43
+
44
+ /**
45
+ * The user's app-wide text-size setting.
46
+ *
47
+ * Five tiers, not the thirteen `fontSizeMap` defines: the extra sizes exist so a
48
+ * heading can step one above body text, but only these five are offerable as a
49
+ * global preference.
50
+ */
51
+ export const FONT_SIZE_PROFILES = ["xs", "sm", "md", "lg", "xl"] as const;
52
+ export type FontSizeProfile = (typeof FONT_SIZE_PROFILES)[number];
53
+
54
+ /** Every size key `fontSizeMap` understands, including the heading-only tiers. */
55
+ export const FONT_SIZE_KEYS = [
56
+ "xs",
57
+ "sm",
58
+ "md",
59
+ "lg",
60
+ "xl",
61
+ "2xl",
62
+ "3xl",
63
+ "4xl",
64
+ "5xl",
65
+ "6xl",
66
+ "7xl",
67
+ "8xl",
68
+ "9xl",
69
+ ] as const;
70
+ export type FontSizeKey = (typeof FONT_SIZE_KEYS)[number];
71
+
72
+ /**
73
+ * The icon size vocabulary.
74
+ *
75
+ * Deliberately the Font Awesome scale, because ~150 call sites in the
76
+ * originating app are written against it and silently changing what `"2x"`
77
+ * means would have been an invisible, app-wide visual change. It is just a set
78
+ * of names here — no icon library is implied by using them.
79
+ *
80
+ * It covers **all** of Font Awesome's `SizeProp`, `2xs` and `2xl` included.
81
+ * That completeness is the point: an adapter that maps its library's size type
82
+ * onto this one has to be able to, and an incomplete union turns into a type
83
+ * error at every call site that happens to use a missing value. `md` is the one
84
+ * addition, an alias for `1x`.
85
+ *
86
+ * It lives here rather than beside `StyledIcon` because `StyleConfig` names it —
87
+ * the app-wide default icon size is a host setting — and having the config
88
+ * import the component that imports the config would be a cycle.
89
+ */
90
+ export const ICON_SIZES = [
91
+ "2xs",
92
+ "xs",
93
+ "sm",
94
+ "1x",
95
+ "md",
96
+ "lg",
97
+ "2x",
98
+ "xl",
99
+ "2xl",
100
+ "3x",
101
+ "4x",
102
+ "5x",
103
+ "6x",
104
+ "7x",
105
+ "8x",
106
+ "9x",
107
+ "10x",
108
+ ] as const;
109
+ export type IconSize = (typeof ICON_SIZES)[number];
110
+
111
+ export function isThemeVariant(value: unknown): value is ThemeVariant {
112
+ return THEME_VARIANTS.includes(value as ThemeVariant);
113
+ }
114
+
115
+ export function isFontSizeProfile(value: unknown): value is FontSizeProfile {
116
+ return FONT_SIZE_PROFILES.includes(value as FontSizeProfile);
117
+ }
118
+
119
+ /**
120
+ * How tightly the UI packs. A user preference, not a viewport thing — someone
121
+ * with limited dexterity picks `comfortable` on a phone, and someone managing a
122
+ * dense list picks `compact` on a desktop.
123
+ *
124
+ * It changes more than padding: at `compact` the intent buttons drop their
125
+ * text label and show only their icon, which is why the shared components need
126
+ * to know about it rather than the host handling it alone.
127
+ */
128
+ export const DENSITY_PROFILES = ["compact", "normal", "comfortable"] as const;
129
+ export type DensityProfile = (typeof DENSITY_PROFILES)[number];
130
+
131
+ export function isDensityProfile(value: unknown): value is DensityProfile {
132
+ return DENSITY_PROFILES.includes(value as DensityProfile);
133
+ }
134
+
135
+ export function isIconSize(value: unknown): value is IconSize {
136
+ return ICON_SIZES.includes(value as IconSize);
137
+ }
package/src/index.ts ADDED
@@ -0,0 +1,259 @@
1
+ /**
2
+ * @stonedogcode/style — public API.
3
+ *
4
+ * Components are exported both as named exports and, individually, as default
5
+ * exports from their own module. Prefer the named export; the default exports
6
+ * exist because the originating codebase used them at ~1,400 call sites and
7
+ * changing that was not worth bundling into the extraction.
8
+ *
9
+ * The Panda preset is NOT re-exported here. It is imported by the consumer's
10
+ * `panda.config.ts`, which runs in Node at build time, and pulling the whole
11
+ * component tree (and React with it) into that context is a needless cost —
12
+ * hence the separate `@stonedogcode/style/preset` entry point.
13
+ */
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Configuration seam — what a host application must wire up.
17
+ // ---------------------------------------------------------------------------
18
+ export {
19
+ StonedogStyleProvider,
20
+ useStyleConfig,
21
+ useFontSizeProfile,
22
+ useIconSize,
23
+ useResolvedVariant,
24
+ DEFAULT_STYLE_CONFIG,
25
+ } from "./config/style-config";
26
+ export type {
27
+ StyleConfig,
28
+ StonedogStyleProviderProps,
29
+ } from "./config/style-config";
30
+
31
+ /**
32
+ * Deprecated `Hopper*` aliases — NEH-251. See `config/style-config.tsx`.
33
+ * Removed once every consumer has landed its rename PR.
34
+ */
35
+ export { HopperStyleProvider } from "./config/style-config";
36
+ export type { HopperStyleProviderProps } from "./config/style-config";
37
+
38
+ export { setStyleLogger } from "./config/logger";
39
+ export type { StyleLogger } from "./config/logger";
40
+
41
+ export {
42
+ fontSizeMap,
43
+ getFontSizeLabel,
44
+ getFontSizeValue,
45
+ stepUpFontSize,
46
+ FONT_SIZE_ORDER,
47
+ } from "./config/font-size";
48
+
49
+ export {
50
+ THEME_VARIANTS,
51
+ STYLE_VARIANTS,
52
+ TEXT_VARIANTS,
53
+ ALL_VARIANTS,
54
+ FONT_SIZE_PROFILES,
55
+ FONT_SIZE_KEYS,
56
+ ICON_SIZES,
57
+ isThemeVariant,
58
+ isFontSizeProfile,
59
+ isIconSize,
60
+ } from "./config/types";
61
+ export type {
62
+ ThemeVariant,
63
+ StyleVariant,
64
+ AllowedVariant,
65
+ AllowedTextVariant,
66
+ FontSizeProfile,
67
+ FontSizeKey,
68
+ IconSize,
69
+ } from "./config/types";
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Layout primitives
73
+ // ---------------------------------------------------------------------------
74
+ export { default as StyledBox, StyledBox as Box } from "./components/StyledBox";
75
+ export type { StyledBoxProps } from "./components/StyledBox";
76
+
77
+ export { default as StyledFlex } from "./components/StyledFlex";
78
+ export type { StyledFlexProps } from "./components/StyledFlex";
79
+
80
+ export { default as StyledGrid } from "./components/StyledGrid";
81
+ export type { StyledGridProps } from "./components/StyledGrid";
82
+
83
+ export { default as StyledGridItem } from "./components/StyledGridItem";
84
+ export type { StyledGridItemProps } from "./components/StyledGridItem";
85
+
86
+ export { default as StyledSimpleGrid } from "./components/StyledSimpleGrid";
87
+
88
+ export { default as StyledStack } from "./components/StyledStack";
89
+ export type { StyledStackProps } from "./components/StyledStack";
90
+
91
+ export { default as StyledHStack } from "./components/StyledHStack";
92
+ export type { StyledHStackProps } from "./components/StyledHStack";
93
+
94
+ export { default as StyledVStack } from "./components/StyledVStack";
95
+ export type { StyledVStackProps } from "./components/StyledVStack";
96
+
97
+ export { default as StyledScrollbar } from "./components/StyledScrollbar";
98
+ export { default as StyledSidebar, StyledSidebar as Sidebar } from "./components/StyledSidebar";
99
+ export type { StyledSidebarProps, SidebarItem } from "./components/StyledSidebar";
100
+ export { default as StyledCollapsible } from "./components/StyledCollapsible";
101
+ export type { StyledCollapsibleProps } from "./components/StyledCollapsible";
102
+
103
+ export { default as StyledFooter, StyledFooter as Footer } from "./components/StyledFooter";
104
+ export type {
105
+ StyledFooterProps,
106
+ StyledFooterVersion,
107
+ StyledFooterStatusBadge,
108
+ } from "./components/StyledFooter";
109
+ export type { StyledScrollbarProps } from "./components/StyledScrollbar";
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Typography & dividers
113
+ // ---------------------------------------------------------------------------
114
+ export { default as StyledText } from "./components/StyledText";
115
+ export type { StyledTextProps } from "./components/StyledText";
116
+
117
+ export { default as StyledHeading } from "./components/StyledHeading";
118
+
119
+ export { default as StyledSeparator } from "./components/StyledSeparator";
120
+ export type { StyledSeparatorProps } from "./components/StyledSeparator";
121
+
122
+ export { default as StyledHrRule } from "./components/StyledHrRule";
123
+ export type { StyledHrRuleProps } from "./components/StyledHrRule";
124
+
125
+ export {
126
+ default as TitleLogo,
127
+ TITLE_LOGO_METRICS,
128
+ TITLE_LOGO_SIZES,
129
+ isTitleLogoSize,
130
+ } from "./components/TitleLogo";
131
+ export type { TitleLogoProps, TitleLogoSize } from "./components/TitleLogo";
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Icons — the seam, not the artwork. See the README.
135
+ // ---------------------------------------------------------------------------
136
+ export { default as StyledIcon } from "./components/StyledIcon";
137
+ // `IconSize` is exported above, from `config/types` — it is a config-level
138
+ // vocabulary now that `StyleConfig` names it. `StyledIcon` still re-exports it
139
+ // so the older import path keeps working for consumers.
140
+ export type { StyledIconProps } from "./components/StyledIcon";
141
+ export { createIcon, createIconFromComponent } from "./components/create-icon";
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Overlay
145
+ // ---------------------------------------------------------------------------
146
+ export * from "./components/intent-buttons";
147
+ export { createIntentButton } from "./components/create-intent-button";
148
+ export type { IntentButtonProps, IntentButtonSpec } from "./components/create-intent-button";
149
+
150
+ export {
151
+ IntentIconProvider,
152
+ useIntentIcon,
153
+ useIntentIcons,
154
+ missingIntentIcons,
155
+ ICON_INTENTS,
156
+ } from "./config/intent-icons";
157
+ export type { IconIntent, IntentIcons } from "./config/intent-icons";
158
+
159
+ export { useDensity, useDensityStep } from "./config/style-config";
160
+ export { DENSITY_PROFILES, isDensityProfile } from "./config/types";
161
+ export type { DensityProfile } from "./config/types";
162
+ export {
163
+ DENSITY_STEPS,
164
+ DENSITY_BASES,
165
+ DENSITY_METRICS,
166
+ densityCustomProperties,
167
+ isDensityBase,
168
+ isDensityStep,
169
+ resolveDensityStep,
170
+ } from "./config/density";
171
+ export type { DensityBase, DensityStep } from "./config/density";
172
+
173
+ export { default as StyledButton } from "./components/StyledButton";
174
+ export type { StyledButtonProps } from "./components/StyledButton";
175
+
176
+ export { default as StyledIconButton } from "./components/StyledIconButton";
177
+ export type { StyledIconButtonProps, IconButtonSize } from "./components/StyledIconButton";
178
+
179
+ export { default as StyledSpinner } from "./components/StyledSpinner";
180
+ export type { StyledSpinnerProps } from "./components/StyledSpinner";
181
+
182
+ export { default as StyledTooltip } from "./components/StyledTooltip";
183
+ // Exported so a host can make the same decision for its own controls. A product
184
+ // that renders its own hover-revealed affordance has the identical problem, and
185
+ // re-deriving "can this device hover" per app is how two answers appear.
186
+ export { useCanHover } from "./config/can-hover";
187
+ export type { StyledTooltipProps } from "./components/StyledTooltip";
188
+
189
+ // ---------------------------------------------------------------------------
190
+ // Form controls
191
+ // ---------------------------------------------------------------------------
192
+ export { default as StyledFormLabel } from "./components/StyledFormLabel";
193
+ export type { StyledFormLabelProps } from "./components/StyledFormLabel";
194
+
195
+ export { default as StyledInputBool } from "./components/StyledInputBool";
196
+ export type { StyledInputBoolProps, InputBoolVariant } from "./components/StyledInputBool";
197
+ export { INPUT_BOOL_VARIANTS } from "./components/StyledInputBool";
198
+
199
+ export { default as StyledInputSlider } from "./components/StyledInputSlider";
200
+ export type { StyledInputSliderProps } from "./components/StyledInputSlider";
201
+
202
+ // ---------------------------------------------------------------------------
203
+ // Text inputs — dictation is supplied by the host, never implemented here
204
+ // ---------------------------------------------------------------------------
205
+ export type { Dictation } from "./components/dictation";
206
+
207
+ export { default as StyledInputText } from "./components/StyledInputText";
208
+ export type { StyledInputTextProps, InputTextVariant } from "./components/StyledInputText";
209
+ export { INPUT_TEXT_VARIANTS } from "./components/StyledInputText";
210
+
211
+ export { default as StyledInputTextArea } from "./components/StyledInputTextArea";
212
+ export type { StyledInputTextAreaProps } from "./components/StyledInputTextArea";
213
+ export { default as DictationPrompt } from "./components/DictationPrompt";
214
+
215
+ // ---------------------------------------------------------------------------
216
+ // Select + search
217
+ // ---------------------------------------------------------------------------
218
+ export { default as StyledInputSelect } from "./components/StyledInputSelect";
219
+ export type {
220
+ StyledInputSelectProps,
221
+ SelectOption,
222
+ SelectVariant,
223
+ } from "./components/StyledInputSelect";
224
+ export { SELECT_VARIANTS } from "./components/StyledInputSelect";
225
+
226
+ export { default as StyledSearch } from "./components/StyledSearch";
227
+ export type { StyledSearchProps } from "./components/StyledSearch";
228
+
229
+ export { default as StyledInputToggle } from "./components/StyledInputToggle";
230
+ export type { StyledInputToggleProps } from "./components/StyledInputToggle";
231
+
232
+ export { default as StyledInputRadio } from "./components/StyledInputRadio";
233
+ export type { StyledInputRadioProps, RadioItem, RadioVariant } from "./components/StyledInputRadio";
234
+ export { RADIO_VARIANTS } from "./components/StyledInputRadio";
235
+
236
+ export { default as StyledFieldset } from "./components/StyledFieldset";
237
+ export type { StyledFieldsetProps, FieldsetVariant } from "./components/StyledFieldset";
238
+ export { FIELDSET_VARIANTS } from "./components/StyledFieldset";
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Data display
242
+ // ---------------------------------------------------------------------------
243
+ export { default as StyledList } from "./components/StyledList";
244
+ export type {
245
+ StyledListRootProps,
246
+ StyledListItemProps,
247
+ ListVariant,
248
+ } from "./components/StyledList";
249
+ export { LIST_VARIANTS } from "./components/StyledList";
250
+
251
+ export { default as StyledDefinitionList } from "./components/StyledDefinitionList";
252
+ export type {
253
+ StyledDefinitionListProps,
254
+ DlVariant,
255
+ } from "./components/StyledDefinitionList";
256
+ export { DL_VARIANTS } from "./components/StyledDefinitionList";
257
+
258
+ export { default as StyledSparkLine } from "./components/StyledSparkLine";
259
+ export type { StyledSparkLineProps } from "./components/StyledSparkLine";