Skip to content

Commit ba4bccd

Browse files
authored
refactor: update spoiler style structure to use nested properties for particles and solid attributes (#239)
* refactor: update spoiler style structure to use nested properties for particles and solid attributes * refactor: move normalizeColor function to styleUtils and update its usage in markdown styles * refactor: remove mergeSpoilerDefaults function and simplify mergeSubStyle logic * docs: clarify spoiler text overlay behavior in STYLES.md * refactor: move mergeSubStyle function to styleUtils and update its usage in markdown style files
1 parent 92596be commit ba4bccd

12 files changed

Lines changed: 108 additions & 109 deletions

android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerParticleDrawable.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.swmansion.enriched.markdown.spoiler
33
import android.graphics.Canvas
44
import android.graphics.Color
55
import android.graphics.Paint
6-
import com.swmansion.enriched.markdown.styles.SpoilerStyle
76
import kotlin.math.cos
87
import kotlin.math.max
98
import kotlin.math.sin
@@ -30,8 +29,8 @@ class SpoilerParticleDrawable(
3029
private var accumulatedPrimaryBirths = 0f
3130
private var accumulatedSecondaryBirths = 0f
3231

33-
private val densityFactor = particleDensity / SpoilerStyle.DEFAULT_PARTICLE_DENSITY
34-
private val speedFactor = particleSpeed / SpoilerStyle.DEFAULT_PARTICLE_SPEED
32+
private val densityFactor = particleDensity / BASE_PARTICLE_DENSITY
33+
private val speedFactor = particleSpeed / BASE_PARTICLE_SPEED
3534

3635
private var isRevealing = false
3736
private var revealStartTime = -1L
@@ -231,5 +230,8 @@ class SpoilerParticleDrawable(
231230
private const val PARTICLE_LIFETIME = 7
232231
private const val PARTICLE_AGE = 8
233232
private const val STRIDE = 9
233+
234+
private const val BASE_PARTICLE_DENSITY = 8f
235+
private const val BASE_PARTICLE_SPEED = 20f
234236
}
235237
}

android/src/main/java/com/swmansion/enriched/markdown/styles/SpoilerStyle.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ data class SpoilerStyle(
99
val solidBorderRadius: Float,
1010
) {
1111
companion object {
12-
const val DEFAULT_PARTICLE_DENSITY = 8.0f
13-
const val DEFAULT_PARTICLE_SPEED = 20.0f
14-
const val DEFAULT_SOLID_BORDER_RADIUS = 4.0f
15-
1612
fun fromReadableMap(
1713
map: ReadableMap,
1814
parser: StyleParser,
1915
): SpoilerStyle {
2016
val color = parser.parseColor(map, "color")
21-
val particleDensity = parser.parseOptionalDouble(map, "particleDensity", DEFAULT_PARTICLE_DENSITY.toDouble()).toFloat()
22-
val particleSpeed = parser.parseOptionalDouble(map, "particleSpeed", DEFAULT_PARTICLE_SPEED.toDouble()).toFloat()
23-
val solidBorderRadius = parser.parseOptionalDouble(map, "solidBorderRadius", DEFAULT_SOLID_BORDER_RADIUS.toDouble()).toFloat()
24-
return SpoilerStyle(color, particleDensity, particleSpeed, solidBorderRadius)
17+
val particlesMap = map.getMap("particles")!!
18+
val solidMap = map.getMap("solid")!!
19+
return SpoilerStyle(
20+
color = color,
21+
particleDensity = particlesMap.getDouble("density").toFloat(),
22+
particleSpeed = particlesMap.getDouble("speed").toFloat(),
23+
solidBorderRadius = solidMap.getDouble("borderRadius").toFloat(),
24+
)
2525
}
2626
}
2727
}

docs/STYLES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ Styles for inline LaTeX math (`$...$`). Inline math is rendered within the surro
376376
377377
### Spoiler-specific
378378
379-
Styles for spoiler text (`||hidden text||`). Spoiler text is concealed behind an animated particle overlay until the user taps to reveal it.
379+
Styles for spoiler text (`||hidden text||`). Spoiler text is concealed behind an overlay (controlled by the `spoilerOverlay` prop) until the user taps to reveal it.
380380
381381
| Property | Type | Description |
382382
|----------|------|-------------|

ios/styles/StyleConfig.mm

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,6 @@ - (instancetype)init
255255
_tableFontNeedsRecreation = YES;
256256
_tableHeaderFontNeedsRecreation = YES;
257257
_linkUnderline = YES;
258-
_spoilerParticleDensity = 8.0;
259-
_spoilerParticleSpeed = 20.0;
260-
_spoilerSolidBorderRadius = 4.0;
261258
return self;
262259
}
263260

ios/utils/StylePropsUtils.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,18 +1049,18 @@ BOOL applyMarkdownStyleToConfig(StyleConfig *config, const MarkdownStyle &newSty
10491049
changed = YES;
10501050
}
10511051

1052-
if (newStyle.spoiler.particleDensity != oldStyle.spoiler.particleDensity) {
1053-
[config setSpoilerParticleDensity:newStyle.spoiler.particleDensity];
1052+
if (newStyle.spoiler.particles.density != oldStyle.spoiler.particles.density) {
1053+
[config setSpoilerParticleDensity:newStyle.spoiler.particles.density];
10541054
changed = YES;
10551055
}
10561056

1057-
if (newStyle.spoiler.particleSpeed != oldStyle.spoiler.particleSpeed) {
1058-
[config setSpoilerParticleSpeed:newStyle.spoiler.particleSpeed];
1057+
if (newStyle.spoiler.particles.speed != oldStyle.spoiler.particles.speed) {
1058+
[config setSpoilerParticleSpeed:newStyle.spoiler.particles.speed];
10591059
changed = YES;
10601060
}
10611061

1062-
if (newStyle.spoiler.solidBorderRadius != oldStyle.spoiler.solidBorderRadius) {
1063-
[config setSpoilerSolidBorderRadius:newStyle.spoiler.solidBorderRadius];
1062+
if (newStyle.spoiler.solid.borderRadius != oldStyle.spoiler.solid.borderRadius) {
1063+
[config setSpoilerSolidBorderRadius:newStyle.spoiler.solid.borderRadius];
10641064
changed = YES;
10651065
}
10661066

src/EnrichedMarkdownNativeComponent.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,19 @@ interface InlineMathStyleInternal {
137137
color: ColorValue;
138138
}
139139

140+
interface SpoilerParticlesStyleInternal {
141+
density: CodegenTypes.Float;
142+
speed: CodegenTypes.Float;
143+
}
144+
145+
interface SpoilerSolidStyleInternal {
146+
borderRadius: CodegenTypes.Float;
147+
}
148+
140149
interface SpoilerStyleInternal {
141150
color: ColorValue;
142-
particleDensity: CodegenTypes.Float;
143-
particleSpeed: CodegenTypes.Float;
144-
solidBorderRadius: CodegenTypes.Float;
151+
particles: SpoilerParticlesStyleInternal;
152+
solid: SpoilerSolidStyleInternal;
145153
}
146154

147155
export interface MarkdownStyleInternal {

src/EnrichedMarkdownTextNativeComponent.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,19 @@ interface InlineMathStyleInternal {
137137
color: ColorValue;
138138
}
139139

140+
interface SpoilerParticlesStyleInternal {
141+
density: CodegenTypes.Float;
142+
speed: CodegenTypes.Float;
143+
}
144+
145+
interface SpoilerSolidStyleInternal {
146+
borderRadius: CodegenTypes.Float;
147+
}
148+
140149
interface SpoilerStyleInternal {
141150
color: ColorValue;
142-
particleDensity: CodegenTypes.Float;
143-
particleSpeed: CodegenTypes.Float;
144-
solidBorderRadius: CodegenTypes.Float;
151+
particles: SpoilerParticlesStyleInternal;
152+
solid: SpoilerSolidStyleInternal;
145153
}
146154

147155
export interface MarkdownStyleInternal {

src/normalizeMarkdownInputStyle.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { processColor, type ColorValue } from 'react-native';
22
import type { MarkdownInputStyle } from './EnrichedMarkdownInput';
3+
import { normalizeColor } from './styleUtils';
34

45
interface MarkdownInputStyleInternal {
56
strong: {
@@ -18,9 +19,6 @@ interface MarkdownInputStyleInternal {
1819
};
1920
}
2021

21-
const normalizeColor = (color: string | undefined): ColorValue | undefined =>
22-
color ? processColor(color) : undefined;
23-
2422
const DEFAULT_LINK_COLOR = '#2563EB';
2523
const DEFAULT_SPOILER_COLOR = '#374151';
2624
const DEFAULT_SPOILER_BG_COLOR = '#E5E7EB';

src/normalizeMarkdownStyle.ts

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
1-
import { Platform, processColor } from 'react-native';
1+
import { Platform } from 'react-native';
22
import type { MarkdownStyle } from './types/MarkdownStyle';
33
import type {
44
BlockTextAlign,
55
EmphasisFontStyle,
66
MarkdownStyleInternal,
77
} from './types/MarkdownStyleInternal';
8-
import { flattenSpoilerStyle, isStyleEqual } from './styleUtils';
9-
10-
// On native, processColor converts hex strings to ARGB integers the renderer
11-
// expects. On web, CSS accepts hex strings natively — no conversion needed.
12-
// MarkdownStyleInternal types colors as `string`; native consumers
13-
// (EnrichedMarkdownTextNativeComponent) accept `ColorValue` (string | number)
14-
// at runtime, so the ARGB integers processColor produces are handled correctly.
15-
export const normalizeColor = (
16-
color: string | undefined
17-
): string | undefined =>
18-
color
19-
? Platform.OS === 'web'
20-
? color
21-
: ((processColor(color) ?? undefined) as string | undefined)
22-
: undefined;
8+
import { isStyleEqual, normalizeColor, mergeSubStyle } from './styleUtils';
239

2410
const getSystemFont = (): string =>
2511
Platform.select({
@@ -37,25 +23,6 @@ const getMonospaceFont = (): string =>
3723
default: 'monospace',
3824
})!;
3925

40-
function mergeSubStyle<T extends Record<string, unknown>>(
41-
defaultStyle: T,
42-
userStyle?: Partial<T>
43-
): T {
44-
if (!userStyle) return defaultStyle;
45-
const result: Record<string, unknown> = { ...defaultStyle, ...userStyle };
46-
// Normalize any user-supplied color strings. On web this is a no-op (CSS
47-
// accepts hex strings); on native it converts them to ARGB integers.
48-
for (const key in result) {
49-
if (
50-
key.toLowerCase().includes('color') &&
51-
typeof result[key] === 'string'
52-
) {
53-
result[key] = normalizeColor(result[key] as string);
54-
}
55-
}
56-
return result as T;
57-
}
58-
5926
const defaultTextColor = normalizeColor('#1F2937')!;
6027
const defaultHeadingColor = normalizeColor('#111827')!;
6128

@@ -75,7 +42,7 @@ const baseHeader: {
7542
textAlign: 'auto',
7643
};
7744

78-
const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
45+
const DEFAULT_NORMALIZED_STYLE = Object.freeze({
7946
paragraph: {
8047
fontSize: 16,
8148
fontFamily: getSystemFont(),
@@ -234,11 +201,10 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
234201
},
235202
spoiler: {
236203
color: normalizeColor('#374151')!,
237-
particleDensity: 8,
238-
particleSpeed: 20,
239-
solidBorderRadius: 4,
204+
particles: { density: 8, speed: 20 },
205+
solid: { borderRadius: 4 },
240206
},
241-
});
207+
}) as MarkdownStyleInternal;
242208

243209
const refCache = new WeakMap<MarkdownStyle, MarkdownStyleInternal>();
244210
const structuralCache: {
@@ -272,10 +238,9 @@ export const normalizeMarkdownStyle = (
272238
(
273239
Object.keys(DEFAULT_NORMALIZED_STYLE) as (keyof MarkdownStyleInternal)[]
274240
).forEach((key) => {
275-
const userValue =
276-
key === 'spoiler'
277-
? flattenSpoilerStyle(style.spoiler)
278-
: (style[key] as unknown as Record<string, unknown> | undefined);
241+
const userValue = style[key] as unknown as
242+
| Record<string, unknown>
243+
| undefined;
279244
result[key] = mergeSubStyle(
280245
DEFAULT_NORMALIZED_STYLE[key] as unknown as Record<string, unknown>,
281246
userValue as Record<string, unknown> | undefined

src/normalizeMarkdownStyle.web.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,13 @@ import type {
44
EmphasisFontStyle,
55
MarkdownStyleInternal,
66
} from './types/MarkdownStyleInternal';
7-
import { flattenSpoilerStyle, isStyleEqual } from './styleUtils';
7+
import { isStyleEqual, mergeSubStyle } from './styleUtils';
88

99
const SYSTEM_FONT =
1010
'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1111
const MONOSPACE_FONT =
1212
'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace';
1313

14-
function mergeSubStyle<T extends Record<string, unknown>>(
15-
defaultStyle: T,
16-
userStyle?: Partial<T>
17-
): T {
18-
if (!userStyle) return defaultStyle;
19-
return { ...defaultStyle, ...userStyle };
20-
}
21-
2214
const defaultTextColor = '#1F2937';
2315
const defaultHeadingColor = '#111827';
2416

@@ -190,9 +182,8 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
190182
// Spoiler rendering is not supported on web yet — defaults kept for type compatibility.
191183
spoiler: {
192184
color: '#374151',
193-
particleDensity: 8,
194-
particleSpeed: 20,
195-
solidBorderRadius: 4,
185+
particles: { density: 8, speed: 20 },
186+
solid: { borderRadius: 4 },
196187
},
197188
});
198189

@@ -228,10 +219,9 @@ export const normalizeMarkdownStyle = (
228219
(
229220
Object.keys(DEFAULT_NORMALIZED_STYLE) as (keyof MarkdownStyleInternal)[]
230221
).forEach((key) => {
231-
const userValue =
232-
key === 'spoiler'
233-
? flattenSpoilerStyle(style.spoiler)
234-
: (style[key] as unknown as Record<string, unknown> | undefined);
222+
const userValue = style[key] as unknown as
223+
| Record<string, unknown>
224+
| undefined;
235225
result[key] = mergeSubStyle(
236226
DEFAULT_NORMALIZED_STYLE[key] as unknown as Record<string, unknown>,
237227
userValue as Record<string, unknown> | undefined

0 commit comments

Comments
 (0)