Skip to content

Commit 6d6109a

Browse files
authored
Feature adding an on DSL for more declaritive responsive styles (#55)
* Add SwiftUI-like DSL syntax for responsive styling Implements #45 by adding a result builder pattern for responsive styling that allows for a more natural, SwiftUI-like syntax without bash references. The implementation maintains backwards compatibility with existing code by overloading the responsive method.
1 parent 0e231e3 commit 6d6109a

File tree

93 files changed

+7410
-4099
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+7410
-4099
lines changed

.github/ISSUE_TEMPLATE/02_FEATURE_REQUEST.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ assignees: ''
3131
- [ ] Extension to Existing Element
3232
- [ ] Performance Improvement
3333
- [ ] Documentation Enhancement
34+
- [ ] Developer Experience Enhancement
3435
- [ ] Other (please specify)
3536

3637
## Example Code

CONTRIBUTING.md

Lines changed: 120 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,10 @@ WebUI follows a compositional pattern for creating HTML elements. When adding a
215215

216216
## Adding New Style Modifiers
217217

218-
Style modifiers in WebUI follow an extension pattern on the `Element` class. Here's how to add a new style modifier:
218+
Style modifiers in WebUI follow the unified style system pattern. Here's how to add a new style modifier:
219219

220220
1. **File Location**: Add the new style modifier to the appropriate file in `Sources/WebUI/Styles/`:
221+
- Core style operations go in the `Core/` directory
221222
- Appearance-related modifiers go in the `Appearance/` directory
222223
- Layout-related modifiers go in the `Base/` or `Positioning/` directories
223224
- Create a new file if the modifier doesn't fit an existing category
@@ -238,7 +239,33 @@ Style modifiers in WebUI follow an extension pattern on the `Element` class. Her
238239
}
239240
```
240241

241-
b. **Implement the Extension Method**:
242+
b. **Implement the Style Operation**:
243+
```swift
244+
/// Style operation for the custom style
245+
public struct StyleModifierOperation: StyleOperation {
246+
/// Parameters for this style operation
247+
public struct Parameters {
248+
public let option: StyleOption
249+
250+
public init(option: StyleOption) {
251+
self.option = option
252+
}
253+
}
254+
255+
/// Applies the style operation and returns CSS classes
256+
public func applyClasses(params: Parameters) -> [String] {
257+
return ["style-\(params.option.rawValue)"]
258+
}
259+
260+
/// Shared instance
261+
public static let shared = StyleModifierOperation()
262+
263+
/// Private initializer
264+
private init() {}
265+
}
266+
```
267+
268+
c. **Implement the Element Extension Method**:
242269
```swift
243270
extension Element {
244271
/// Applies a style modifier to the element.
@@ -260,43 +287,45 @@ Style modifiers in WebUI follow an extension pattern on the `Element` class. Her
260287
option: StyleOption,
261288
on modifiers: Modifier...
262289
) -> Element {
263-
let baseClass = "style-\(option.rawValue)"
264-
let newClasses = combineClasses([baseClass], withModifiers: modifiers)
265-
266-
return Element(
267-
tag: self.tag,
268-
id: self.id,
269-
classes: (self.classes ?? []) + newClasses,
270-
role: self.role,
271-
label: self.label,
272-
data: self.data,
273-
isSelfClosing: self.isSelfClosing,
274-
customAttributes: self.customAttributes,
275-
content: self.contentBuilder
290+
let params = StyleModifierOperation.Parameters(option: option)
291+
292+
return StyleModifierOperation.shared.applyToElement(
293+
self,
294+
params: params,
295+
modifiers: modifiers
276296
)
277297
}
278298
}
279299
```
280300

281-
c. **Update Responsive Support** (if applicable):
301+
d. **Implement the Global Function for Declarative DSL**:
282302
```swift
283-
extension Element {
284-
/// Responsive version for use within the .responsive block
285-
@discardableResult
286-
public func styleModifier(option: StyleOption) -> Element {
287-
return self.styleModifier(option: option, on: []).proxy()
288-
}
303+
/// Applies the style modifier in the responsive context with Declarative syntax.
304+
///
305+
/// - Parameters:
306+
/// - option: The style option to apply.
307+
/// - Returns: A responsive modification for the style.
308+
public func styleModifier(option: StyleOption) -> ResponsiveModification {
309+
let params = StyleModifierOperation.Parameters(option: option)
310+
311+
return StyleModifierOperation.shared.asModification(params: params)
289312
}
290313
```
291314

315+
f. **Register in StyleRegistry** (optional but recommended):
316+
```swift
317+
// In StyleRegistry.swift
318+
public static let styleModifier = StyleModifierOperation.shared
319+
```
320+
292321
3. **Testing**: Add unit tests for the new style modifier in the `Tests` directory.
293322

294323
4. **Documentation**: Include comprehensive DocC documentation with:
295324
- Method-level documentation explaining the modifier's purpose
296325
- Parameter documentation for all method parameters
297326
- Usage examples showing common implementations
298327
- Visual examples if the style has a significant impact on appearance
299-
- Examples of using the modifier within responsive blocks
328+
- Examples of using the modifier with all three interfaces (direct, on, and Declarative)
300329

301330
### Adding Extensions to Existing Elements
302331

@@ -332,30 +361,62 @@ You can extend existing elements with specialized methods to improve developer e
332361

333362
3. **Documentation**: As with other additions, include comprehensive DocC documentation.
334363

335-
### Using Responsive Styling
336-
337-
WebUI provides a block-based responsive API for cleaner responsive designs.
338-
339-
### Basic Usage
340-
341-
The `.responsive` modifier allows applying multiple style changes across different breakpoints in a single block:
342-
343-
```swift
344-
Text { "Responsive Content" }
345-
.font(size: .sm)
346-
.background(color: .neutral(._500))
347-
.responsive {
348-
$0.md {
349-
$0.font(size: .lg)
350-
$0.background(color: .neutral(._700))
351-
$0.padding(of: 4)
352-
}
353-
$0.lg {
354-
$0.font(size: .xl)
355-
$0.background(color: .neutral(._900))
356-
}
357-
}
358-
```
364+
## Responsive Styling System
365+
366+
WebUI provides a powerful responsive styling system with multiple syntaxes for flexibility and developer experience.
367+
368+
### Responsive Styling Options
369+
370+
WebUI supports two different ways to apply responsive styles:
371+
372+
1. **Declarative Block Syntax** - Create responsive styles in a clean, concise way:
373+
1. **Declaritive** (using the result builder pattern):
374+
```swift
375+
Text { "Responsive Content" }
376+
.font(size: .sm)
377+
.responsive {
378+
md {
379+
font(size: .lg)
380+
background(color: .neutral(._700))
381+
}
382+
lg {
383+
font(size: .xl)
384+
padding(of: 6)
385+
}
386+
}
387+
```
388+
389+
2. **Direct Breakpoint Modifiers** (for single property changes):
390+
```swift
391+
Text { "Responsive Content" }
392+
.font(size: .sm, on: .xs)
393+
.font(size: .lg, on: .md)
394+
.font(size: .xl, on: .lg)
395+
```
396+
397+
### Implementing Responsive Support
398+
399+
When adding new style modifiers, you must implement both interfaces to ensure full responsive support:
400+
401+
1. **Element Extension** - For direct styling and breakpoint modifiers
402+
2. **Global Function** - For Declaritive syntax with result builders
403+
404+
The unified style system makes this process simple by deriving both interfaces from a single style operation.
405+
406+
### Unified Style System
407+
408+
WebUI uses a unified style system that defines each style operation once and derives multiple interfaces from it:
409+
410+
1. **Core Style Operations** - Define the core logic for generating CSS classes
411+
2. **Interface Adapters** - Adapt the core operations to different contexts (Element extensions and global functions)
412+
3. **StyleRegistry** - Provides centralized access to all style operations
413+
414+
This approach provides several benefits:
415+
- Single point of definition for each style
416+
- Consistency across different interfaces
417+
- Reduced code duplication
418+
- Easier maintenance and extension
419+
- Clean, Declarative syntax for responsive styling
359420

360421
### File Organization Principles
361422

@@ -367,18 +428,21 @@ When organizing code in the WebUI library, follow these principles:
367428
4. **Manageable Size**: Keep files under on the smaller side where possible
368429
5. **Clear Dependencies**: Make dependencies between components explicit and avoid circularity
369430

370-
When refactoring or adding new code, consider if you should:
371-
- Add to an existing file (for small, closely related additions)
372-
- Create a new file in an existing directory (for new components in an established category)
373-
- Create a new directory (for entirely new subsystems or categories)
431+
When adding new style operations:
432+
- Create the style operation in `Styles/Core/`
433+
- Register it in `StyleRegistry`
434+
- Implement the three interface adapters (Element, ResponsiveBuilder, global function)
435+
- Add comprehensive documentation and tests
436+
437+
### Style Operation File Structure
374438

375-
### Adding Support to Custom Style Methods
439+
Each style operation file should follow this structure:
376440

377-
When creating custom style modifiers, ensure they work within responsive blocks by:
441+
1. **Style Operation Implementation** - The core logic for generating CSS classes
442+
2. **Element Extension** - For direct styling with the `on: modifiers` parameter
443+
3. **Global Function** - For Declarative syntax within responsive blocks
378444

379-
1. Adding a version without the `on modifiers` parameter
380-
2. Using the `.proxy()` method to maintain the proper element chain
381-
3. Adding examples showing how to use the style in responsive contexts
445+
This structure ensures full support across both interfaces and maintains consistency across the codebase.
382446

383447
## Styleguides
384448

Sources/WebUI/Documentation.docc/Extensions/Date.md

Lines changed: 0 additions & 12 deletions
This file was deleted.

Sources/WebUI/Documentation.docc/Extensions/String.md

Lines changed: 0 additions & 21 deletions
This file was deleted.

Sources/WebUI/Documentation.docc/Resources/code-files/about-page.swift

Lines changed: 0 additions & 73 deletions
This file was deleted.

Sources/WebUI/Documentation.docc/Resources/code-files/application-main.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)