@visualli/core 0.2.3 → 0.2.4

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.
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-GQMFBYLK.js";
15
15
  import {
16
16
  ideaColor
17
- } from "./chunk-2EVIMAJN.js";
17
+ } from "./chunk-WE7UEUEW.js";
18
18
  import {
19
19
  TOKENS,
20
20
  TOPICS
@@ -526,4 +526,4 @@ export {
526
526
  createMindMapConfig,
527
527
  generateSampleConfig
528
528
  };
529
- //# sourceMappingURL=chunk-RLZO3KIN.js.map
529
+ //# sourceMappingURL=chunk-L5BTWXFR.js.map
@@ -16,6 +16,10 @@ function topicFor(color, siblingIndex) {
16
16
  if (!color || !color.trim()) return TOPIC_ORDER[(siblingIndex % TOPIC_ORDER.length + TOPIC_ORDER.length) % TOPIC_ORDER.length];
17
17
  return topicFromName(color);
18
18
  }
19
+ var IMMERSION = {
20
+ /** Renderers draw it by default. */
21
+ defaultOn: true
22
+ };
19
23
  var CUSTOM = {
20
24
  /** The ring is the fill with each RGB channel multiplied by this. */
21
25
  ringShade: 0.78
@@ -77,6 +81,7 @@ export {
77
81
  TOPIC_ORDER,
78
82
  topicFromName,
79
83
  topicFor,
84
+ IMMERSION,
80
85
  CUSTOM,
81
86
  customColor,
82
87
  isThemeName,
@@ -93,4 +98,4 @@ export {
93
98
  ideaColor,
94
99
  ideaStyle
95
100
  };
96
- //# sourceMappingURL=chunk-2EVIMAJN.js.map
101
+ //# sourceMappingURL=chunk-WE7UEUEW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/generated/geometry/color.ts","../src/theme/index.ts"],"sourcesContent":["// Generated from visualli.ai design-system/components/src/color.ts — do not edit here.\n/* Which topic an idea is drawn in. A `.visualli` file's `data.color` may name one of the eight topics or be any\n other color, or be missing. Every renderer resolves it with this rule, so a file looks the same everywhere:\n a topic name ('teal', 'Harbor ') → that topic (case and surrounding spaces don't matter);\n no color → the topics in order, by the idea's position among its siblings (so siblings differ);\n anything else (e.g. '#b7e7f3') → null: not a topic — drawn as given (customColor): the color as the fill, and\n the fill darkened (CUSTOM.ringShade) as the ring; a custom color doesn't follow themes.\n No dependencies, so it can travel alone. */\n\n/** The eight topics, in the order missing colors cycle through. */\nexport const TOPIC_ORDER = ['teal', 'harbor', 'iris', 'berry', 'coral', 'amber', 'sun', 'stone'] as const;\nexport type TopicName = (typeof TOPIC_ORDER)[number];\n\n/** The topic a color names, or null. */\nexport function topicFromName(color: string | null | undefined): TopicName | null {\n if (!color) return null;\n const c = color.trim().toLowerCase();\n return (TOPIC_ORDER as readonly string[]).includes(c) ? (c as TopicName) : null;\n}\n\n/** The topic for an idea: its named topic; with no color, the next topic in sibling order; null for any other color. */\nexport function topicFor(color: string | null | undefined, siblingIndex: number): TopicName | null {\n if (!color || !color.trim()) return TOPIC_ORDER[((siblingIndex % TOPIC_ORDER.length) + TOPIC_ORDER.length) % TOPIC_ORDER.length];\n return topicFromName(color);\n}\n\n/** Chromatic immersion: inside a layer, the canvas takes the fill of the idea you stepped into (at the `immersion-alpha`\n * token), so you always know whose inside you are in. Part of the spec, so it is on unless a host turns it off. */\nexport const IMMERSION = { /** Renderers draw it by default. */ defaultOn: true } as const;\n\n/** A custom (non-topic) color: drawn as given, with a darker ring. */\nexport const CUSTOM = { /** The ring is the fill with each RGB channel multiplied by this. */ ringShade: 0.78 } as const;\n\n/** Fill and ring for a custom color. `ring` is null when the color isn't a 6-digit hex (use the `edge` token then). */\nexport function customColor(color: string): { fill: string; ring: string | null } {\n const m = /^#?([0-9a-f]{6})$/i.exec((color || '').trim());\n if (!m) return { fill: color, ring: null };\n const n = parseInt(m[1], 16), f = CUSTOM.ringShade;\n const r = Math.round(((n >> 16) & 255) * f), g = Math.round(((n >> 8) & 255) * f), b = Math.round((n & 255) * f);\n return { fill: color.trim(), ring: '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1) };\n}\n","// ─── Theme resolution ────────────────────────────────────────────────────────\n//\n// Everything visual comes from the generated design-system modules. This file\n// only decides WHICH of the 8 themes applies and resolves document colours with\n// the design system's colour rule. No colour literals live here.\n//\n// Dependencies: ../generated/designSystem.ts (generated from design-system/).\n\nimport {\n CANVAS_STYLE,\n DESIGN_SYSTEM_VERSION,\n METRICS,\n METRICS_REDUCED_MOTION,\n THEME_NAMES,\n TOKENS,\n TOPICS,\n TYPE_STYLES,\n type ThemeName,\n type TopicName,\n} from '../generated/designSystem.js';\nimport { TOPIC_ORDER, customColor, topicFor, topicFromName } from '../generated/geometry/color.js';\n\nexport { topicFromName, customColor };\n\nexport { CANVAS_STYLE, DESIGN_SYSTEM_VERSION, METRICS, METRICS_REDUCED_MOTION, THEME_NAMES, TOKENS, TOPICS, TYPE_STYLES };\nexport type { ThemeName, TopicName };\n\n// ── Theme selection ───────────────────────────────────────────────────────────\n\n/** Theme families: each resolves to its light or dark member. */\nexport type ThemeFamily = 'standard' | 'focus' | 'colorsafe' | 'contrast';\n\n/**\n * Anything a consumer may pass as `theme`:\n * - one of the 8 design-system themes ('light', 'dark', 'focus-light', ...)\n * - a family name ('focus' | 'colorsafe' | 'contrast') -> light/dark per the reader's scheme\n * - 'auto' -> light/dark per prefers-color-scheme (contrast under forced-colors)\n *\n * 'light' | 'dark' | 'auto' are the pre-0.2 values, kept as aliases for one release.\n */\nexport type ThemeInput = ThemeName | 'auto' | 'focus' | 'colorsafe' | 'contrast';\n\nexport interface ThemeEnv {\n /** prefers-color-scheme: dark */\n prefersDark?: boolean;\n /** forced-colors: active (Windows high contrast etc.) */\n forcedColors?: boolean;\n}\n\nconst FAMILIES: ReadonlySet<string> = new Set(['focus', 'colorsafe', 'contrast']);\n\nexport function isThemeName(v: unknown): v is ThemeName {\n return typeof v === 'string' && (THEME_NAMES as readonly string[]).includes(v);\n}\n\n/** Resolve any accepted `theme` value to one concrete design-system theme. */\nexport function resolveTheme(input: ThemeInput | undefined, env: ThemeEnv = {}): ThemeName {\n const scheme = env.prefersDark ? 'dark' : 'light';\n if (input === undefined || input === 'auto') return env.forcedColors ? (`contrast-${scheme}` as ThemeName) : scheme;\n if (FAMILIES.has(input)) return `${input}-${scheme}` as ThemeName;\n return isThemeName(input) ? input : 'light';\n}\n\nexport const isDarkTheme = (name: ThemeName): boolean => name.endsWith('dark');\nexport const isContrastTheme = (name: ThemeName): boolean => name.startsWith('contrast');\nexport const isFocusTheme = (name: ThemeName): boolean => name.startsWith('focus');\n\n/** All tokens of a theme (already merged over the light defaults). */\nexport const getTokens = (name: ThemeName): Readonly<Record<string, string>> => TOKENS[name];\n\n/** One token of a theme. Throws on an unknown key so typos fail loudly in tests. */\nexport function token(name: ThemeName, key: string): string {\n const v = TOKENS[name][key];\n if (v === undefined) throw new Error(`Unknown design-system token \"${key}\"`);\n return v;\n}\n\n// ── Comfort settings ──────────────────────────────────────────────────────────\n\nexport interface Comfort {\n /** Atkinson Hyperlegible for map labels instead of the handwritten faces (`data-type=\"readable\"`). */\n readableType?: boolean;\n /** Larger UI and label text (`data-scale=\"lg\"`). */\n largerText?: boolean;\n /** Skip transitions and reveal animations (`data-motion=\"reduced\"`). 'system' follows prefers-reduced-motion. */\n reducedMotion?: boolean | 'system';\n}\n\nexport interface ResolvedComfort { readableType: boolean; largerText: boolean; reducedMotion: boolean }\n\nexport function resolveComfort(c: Comfort | undefined, env: { prefersReducedMotion?: boolean } = {}): ResolvedComfort {\n const rm = c?.reducedMotion;\n return {\n readableType: !!c?.readableType,\n largerText: !!c?.largerText,\n reducedMotion: rm === undefined || rm === 'system' ? !!env.prefersReducedMotion : rm,\n };\n}\n\n/** Numeric design-system tokens (px / ms stripped). */\nexport type Metrics = { readonly [K in keyof typeof METRICS]: number };\n\n/** Numeric tokens with the reduced-motion overrides applied when requested. */\nexport function metricsFor(comfort: ResolvedComfort): Metrics {\n return comfort.reducedMotion ? { ...METRICS, ...METRICS_REDUCED_MOTION } : METRICS;\n}\n\n/** Multiplier the spec applies to label sizes under `data-scale=\"lg\"` (`--vi-label-scale`). */\nexport const labelScale = (c: ResolvedComfort): number => (c.largerText ? 1.15 : 1);\n\n// ── Topic palette ─────────────────────────────────────────────────────────────\n\nexport interface TopicStyle { topic: TopicName; fill: string; ring: string }\n\n/** Fill + ring colour of a topic in a theme. */\nexport function topicStyle(theme: ThemeName, topic: TopicName): TopicStyle {\n const t = TOKENS[theme];\n return { topic, fill: t[`topic-${topic}`]!, ring: t[`topic-${topic}-ring`]! };\n}\n\n/** An idea's colour by the design system's colour rule (geometry/color.ts, verbatim): a topic name → that topic; no\n * colour → the topics in sibling order; any other colour → custom, drawn as given (customColor: the colour as the fill,\n * the fill darkened by CUSTOM.ringShade as the ring). A custom colour doesn't follow themes. */\nexport interface IdeaColor { topic: TopicName | null; custom: { fill: string; ring: string | null } | null }\n\nexport function ideaColor(color: string | null | undefined, siblingIndex: number): IdeaColor {\n const topic = topicFor(color, siblingIndex);\n return topic ? { topic, custom: null } : { topic: null, custom: customColor(color!) };\n}\n\n/** Fill + ring an idea is drawn with in a theme: its topic's, or its custom colour (ring: the `edge` token when the\n * colour has no darker shade, i.e. isn't a 6-digit hex). */\nexport function ideaStyle(theme: ThemeName, c: { topic?: TopicName | null; custom?: IdeaColor['custom'] }): { fill: string; ring: string } {\n if (c.custom) return { fill: c.custom.fill, ring: c.custom.ring ?? TOKENS[theme]['edge']! };\n return topicStyle(theme, c.topic ?? TOPIC_ORDER[0]);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/generated/geometry/color.ts","../src/theme/index.ts"],"sourcesContent":["// Generated from visualli.ai design-system/components/src/color.ts — do not edit here.\n/* Which topic an idea is drawn in. A `.visualli` file's `data.color` may name one of the eight topics or be any\n other color, or be missing. Every renderer resolves it with this rule, so a file looks the same everywhere:\n a topic name ('teal', 'Harbor ') → that topic (case and surrounding spaces don't matter);\n no color → the topics in order, by the idea's position among its siblings (so siblings differ);\n anything else (e.g. '#b7e7f3') → null: not a topic — drawn as given (customColor): the color as the fill, and\n the fill darkened (CUSTOM.ringShade) as the ring; a custom color doesn't follow themes.\n No dependencies, so it can travel alone. */\n\n/** The eight topics, in the order missing colors cycle through. */\nexport const TOPIC_ORDER = ['teal', 'harbor', 'iris', 'berry', 'coral', 'amber', 'sun', 'stone'] as const;\nexport type TopicName = (typeof TOPIC_ORDER)[number];\n\n/** The topic a color names, or null. */\nexport function topicFromName(color: string | null | undefined): TopicName | null {\n if (!color) return null;\n const c = color.trim().toLowerCase();\n return (TOPIC_ORDER as readonly string[]).includes(c) ? (c as TopicName) : null;\n}\n\n/** The topic for an idea: its named topic; with no color, the next topic in sibling order; null for any other color. */\nexport function topicFor(color: string | null | undefined, siblingIndex: number): TopicName | null {\n if (!color || !color.trim()) return TOPIC_ORDER[((siblingIndex % TOPIC_ORDER.length) + TOPIC_ORDER.length) % TOPIC_ORDER.length];\n return topicFromName(color);\n}\n\n/** Chromatic immersion: inside a layer, the canvas takes the fill of the idea you stepped into (at the `immersion-alpha`\n * token), so you always know whose inside you are in. Part of the spec, so it is on unless a host turns it off. */\nexport const IMMERSION = { /** Renderers draw it by default. */ defaultOn: true } as const;\n\n/** A custom (non-topic) color: drawn as given, with a darker ring. */\nexport const CUSTOM = { /** The ring is the fill with each RGB channel multiplied by this. */ ringShade: 0.78 } as const;\n\n/** Fill and ring for a custom color. `ring` is null when the color isn't a 6-digit hex (use the `edge` token then). */\nexport function customColor(color: string): { fill: string; ring: string | null } {\n const m = /^#?([0-9a-f]{6})$/i.exec((color || '').trim());\n if (!m) return { fill: color, ring: null };\n const n = parseInt(m[1], 16), f = CUSTOM.ringShade;\n const r = Math.round(((n >> 16) & 255) * f), g = Math.round(((n >> 8) & 255) * f), b = Math.round((n & 255) * f);\n return { fill: color.trim(), ring: '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1) };\n}\n","// ─── Theme resolution ────────────────────────────────────────────────────────\n//\n// Everything visual comes from the generated design-system modules. This file\n// only decides WHICH of the 8 themes applies and resolves document colours with\n// the design system's colour rule. No colour literals live here.\n//\n// Dependencies: ../generated/designSystem.ts (generated from design-system/).\n\nimport {\n CANVAS_STYLE,\n DESIGN_SYSTEM_VERSION,\n METRICS,\n METRICS_REDUCED_MOTION,\n THEME_NAMES,\n TOKENS,\n TOPICS,\n TYPE_STYLES,\n type ThemeName,\n type TopicName,\n} from '../generated/designSystem.js';\nimport { TOPIC_ORDER, customColor, topicFor, topicFromName } from '../generated/geometry/color.js';\n\nexport { topicFromName, customColor };\n\nexport { CANVAS_STYLE, DESIGN_SYSTEM_VERSION, METRICS, METRICS_REDUCED_MOTION, THEME_NAMES, TOKENS, TOPICS, TYPE_STYLES };\nexport type { ThemeName, TopicName };\n\n// ── Theme selection ───────────────────────────────────────────────────────────\n\n/** Theme families: each resolves to its light or dark member. */\nexport type ThemeFamily = 'standard' | 'focus' | 'colorsafe' | 'contrast';\n\n/**\n * Anything a consumer may pass as `theme`:\n * - one of the 8 design-system themes ('light', 'dark', 'focus-light', ...)\n * - a family name ('focus' | 'colorsafe' | 'contrast') -> light/dark per the reader's scheme\n * - 'auto' -> light/dark per prefers-color-scheme (contrast under forced-colors)\n *\n * 'light' | 'dark' | 'auto' are the pre-0.2 values, kept as aliases for one release.\n */\nexport type ThemeInput = ThemeName | 'auto' | 'focus' | 'colorsafe' | 'contrast';\n\nexport interface ThemeEnv {\n /** prefers-color-scheme: dark */\n prefersDark?: boolean;\n /** forced-colors: active (Windows high contrast etc.) */\n forcedColors?: boolean;\n}\n\nconst FAMILIES: ReadonlySet<string> = new Set(['focus', 'colorsafe', 'contrast']);\n\nexport function isThemeName(v: unknown): v is ThemeName {\n return typeof v === 'string' && (THEME_NAMES as readonly string[]).includes(v);\n}\n\n/** Resolve any accepted `theme` value to one concrete design-system theme. */\nexport function resolveTheme(input: ThemeInput | undefined, env: ThemeEnv = {}): ThemeName {\n const scheme = env.prefersDark ? 'dark' : 'light';\n if (input === undefined || input === 'auto') return env.forcedColors ? (`contrast-${scheme}` as ThemeName) : scheme;\n if (FAMILIES.has(input)) return `${input}-${scheme}` as ThemeName;\n return isThemeName(input) ? input : 'light';\n}\n\nexport const isDarkTheme = (name: ThemeName): boolean => name.endsWith('dark');\nexport const isContrastTheme = (name: ThemeName): boolean => name.startsWith('contrast');\nexport const isFocusTheme = (name: ThemeName): boolean => name.startsWith('focus');\n\n/** All tokens of a theme (already merged over the light defaults). */\nexport const getTokens = (name: ThemeName): Readonly<Record<string, string>> => TOKENS[name];\n\n/** One token of a theme. Throws on an unknown key so typos fail loudly in tests. */\nexport function token(name: ThemeName, key: string): string {\n const v = TOKENS[name][key];\n if (v === undefined) throw new Error(`Unknown design-system token \"${key}\"`);\n return v;\n}\n\n// ── Comfort settings ──────────────────────────────────────────────────────────\n\nexport interface Comfort {\n /** Atkinson Hyperlegible for map labels instead of the handwritten faces (`data-type=\"readable\"`). */\n readableType?: boolean;\n /** Larger UI and label text (`data-scale=\"lg\"`). */\n largerText?: boolean;\n /** Skip transitions and reveal animations (`data-motion=\"reduced\"`). 'system' follows prefers-reduced-motion. */\n reducedMotion?: boolean | 'system';\n}\n\nexport interface ResolvedComfort { readableType: boolean; largerText: boolean; reducedMotion: boolean }\n\nexport function resolveComfort(c: Comfort | undefined, env: { prefersReducedMotion?: boolean } = {}): ResolvedComfort {\n const rm = c?.reducedMotion;\n return {\n readableType: !!c?.readableType,\n largerText: !!c?.largerText,\n reducedMotion: rm === undefined || rm === 'system' ? !!env.prefersReducedMotion : rm,\n };\n}\n\n/** Numeric design-system tokens (px / ms stripped). */\nexport type Metrics = { readonly [K in keyof typeof METRICS]: number };\n\n/** Numeric tokens with the reduced-motion overrides applied when requested. */\nexport function metricsFor(comfort: ResolvedComfort): Metrics {\n return comfort.reducedMotion ? { ...METRICS, ...METRICS_REDUCED_MOTION } : METRICS;\n}\n\n/** Multiplier the spec applies to label sizes under `data-scale=\"lg\"` (`--vi-label-scale`). */\nexport const labelScale = (c: ResolvedComfort): number => (c.largerText ? 1.15 : 1);\n\n// ── Topic palette ─────────────────────────────────────────────────────────────\n\nexport interface TopicStyle { topic: TopicName; fill: string; ring: string }\n\n/** Fill + ring colour of a topic in a theme. */\nexport function topicStyle(theme: ThemeName, topic: TopicName): TopicStyle {\n const t = TOKENS[theme];\n return { topic, fill: t[`topic-${topic}`]!, ring: t[`topic-${topic}-ring`]! };\n}\n\n/** An idea's colour by the design system's colour rule (geometry/color.ts, verbatim): a topic name → that topic; no\n * colour → the topics in sibling order; any other colour → custom, drawn as given (customColor: the colour as the fill,\n * the fill darkened by CUSTOM.ringShade as the ring). A custom colour doesn't follow themes. */\nexport interface IdeaColor { topic: TopicName | null; custom: { fill: string; ring: string | null } | null }\n\nexport function ideaColor(color: string | null | undefined, siblingIndex: number): IdeaColor {\n const topic = topicFor(color, siblingIndex);\n return topic ? { topic, custom: null } : { topic: null, custom: customColor(color!) };\n}\n\n/** Fill + ring an idea is drawn with in a theme: its topic's, or its custom colour (ring: the `edge` token when the\n * colour has no darker shade, i.e. isn't a 6-digit hex). */\nexport function ideaStyle(theme: ThemeName, c: { topic?: TopicName | null; custom?: IdeaColor['custom'] }): { fill: string; ring: string } {\n if (c.custom) return { fill: c.custom.fill, ring: c.custom.ring ?? TOKENS[theme]['edge']! };\n return topicStyle(theme, c.topic ?? TOPIC_ORDER[0]);\n}\n"],"mappings":"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","names":[]}
@@ -7,6 +7,11 @@ type TopicName = (typeof TOPIC_ORDER)[number];
7
7
  declare function topicFromName(color: string | null | undefined): TopicName | null;
8
8
  /** The topic for an idea: its named topic; with no color, the next topic in sibling order; null for any other color. */
9
9
  declare function topicFor(color: string | null | undefined, siblingIndex: number): TopicName | null;
10
+ /** Chromatic immersion: inside a layer, the canvas takes the fill of the idea you stepped into (at the `immersion-alpha`
11
+ * token), so you always know whose inside you are in. Part of the spec, so it is on unless a host turns it off. */
12
+ declare const IMMERSION: {
13
+ readonly defaultOn: true;
14
+ };
10
15
  /** A custom (non-topic) color: drawn as given, with a darker ring. */
11
16
  declare const CUSTOM: {
12
17
  readonly ringShade: 0.78;
@@ -96,4 +101,4 @@ declare function ideaStyle(theme: ThemeName, c: {
96
101
  ring: string;
97
102
  };
98
103
 
99
- export { CUSTOM as C, type IdeaColor as I, type Metrics as M, type ResolvedComfort as R, TOPIC_ORDER as T, type Comfort as a, type ThemeEnv as b, type ThemeFamily as c, type ThemeInput as d, type TopicStyle as e, customColor as f, getTokens as g, ideaStyle as h, ideaColor as i, isContrastTheme as j, isDarkTheme as k, isFocusTheme as l, isThemeName as m, labelScale as n, metricsFor as o, resolveTheme as p, topicFor as q, resolveComfort as r, topicFromName as s, token as t, topicStyle as u };
104
+ export { CUSTOM as C, IMMERSION as I, type Metrics as M, type ResolvedComfort as R, TOPIC_ORDER as T, type Comfort as a, type IdeaColor as b, type ThemeEnv as c, type ThemeFamily as d, type ThemeInput as e, type TopicStyle as f, customColor as g, getTokens as h, ideaColor as i, ideaStyle as j, isContrastTheme as k, isDarkTheme as l, isFocusTheme as m, isThemeName as n, labelScale as o, metricsFor as p, resolveTheme as q, resolveComfort as r, topicFor as s, token as t, topicFromName as u, topicStyle as v };
@@ -7,6 +7,11 @@ type TopicName = (typeof TOPIC_ORDER)[number];
7
7
  declare function topicFromName(color: string | null | undefined): TopicName | null;
8
8
  /** The topic for an idea: its named topic; with no color, the next topic in sibling order; null for any other color. */
9
9
  declare function topicFor(color: string | null | undefined, siblingIndex: number): TopicName | null;
10
+ /** Chromatic immersion: inside a layer, the canvas takes the fill of the idea you stepped into (at the `immersion-alpha`
11
+ * token), so you always know whose inside you are in. Part of the spec, so it is on unless a host turns it off. */
12
+ declare const IMMERSION: {
13
+ readonly defaultOn: true;
14
+ };
10
15
  /** A custom (non-topic) color: drawn as given, with a darker ring. */
11
16
  declare const CUSTOM: {
12
17
  readonly ringShade: 0.78;
@@ -96,4 +101,4 @@ declare function ideaStyle(theme: ThemeName, c: {
96
101
  ring: string;
97
102
  };
98
103
 
99
- export { CUSTOM as C, type IdeaColor as I, type Metrics as M, type ResolvedComfort as R, TOPIC_ORDER as T, type Comfort as a, type ThemeEnv as b, type ThemeFamily as c, type ThemeInput as d, type TopicStyle as e, customColor as f, getTokens as g, ideaStyle as h, ideaColor as i, isContrastTheme as j, isDarkTheme as k, isFocusTheme as l, isThemeName as m, labelScale as n, metricsFor as o, resolveTheme as p, topicFor as q, resolveComfort as r, topicFromName as s, token as t, topicStyle as u };
104
+ export { CUSTOM as C, IMMERSION as I, type Metrics as M, type ResolvedComfort as R, TOPIC_ORDER as T, type Comfort as a, type IdeaColor as b, type ThemeEnv as c, type ThemeFamily as d, type ThemeInput as e, type TopicStyle as f, customColor as g, getTokens as h, ideaColor as i, ideaStyle as j, isContrastTheme as k, isDarkTheme as l, isFocusTheme as m, isThemeName as n, labelScale as o, metricsFor as p, resolveTheme as q, resolveComfort as r, topicFor as s, token as t, topicFromName as u, topicStyle as v };
package/dist/index.cjs CHANGED
@@ -60,6 +60,7 @@ __export(index_exports, {
60
60
  HULL: () => HULL,
61
61
  HULL_CLEAR: () => HULL_CLEAR,
62
62
  IDEA: () => IDEA,
63
+ IMMERSION: () => IMMERSION,
63
64
  LABEL_GROWTH: () => LABEL_GROWTH,
64
65
  LAYOUT_SPACING: () => LAYOUT_SPACING,
65
66
  MAX_FRAME_TIME: () => MAX_FRAME_TIME,
@@ -1280,6 +1281,10 @@ function topicFor(color, siblingIndex) {
1280
1281
  if (!color || !color.trim()) return TOPIC_ORDER[(siblingIndex % TOPIC_ORDER.length + TOPIC_ORDER.length) % TOPIC_ORDER.length];
1281
1282
  return topicFromName(color);
1282
1283
  }
1284
+ var IMMERSION = {
1285
+ /** Renderers draw it by default. */
1286
+ defaultOn: true
1287
+ };
1283
1288
  var CUSTOM = {
1284
1289
  /** The ring is the fill with each RGB channel multiplied by this. */
1285
1290
  ringShade: 0.78
@@ -2843,6 +2848,7 @@ function shadowsShown(visibleIdeas) {
2843
2848
  HULL,
2844
2849
  HULL_CLEAR,
2845
2850
  IDEA,
2851
+ IMMERSION,
2846
2852
  LABEL_GROWTH,
2847
2853
  LAYOUT_SPACING,
2848
2854
  MAX_FRAME_TIME,