Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Repository Guidelines

## Project Structure & Module Organization
- `Sources/SwiftUIHTML` holds the reusable rendering core; `Example` contains the SwiftUI host app and its unit/UI test targets.
- `SwiftUIHTMLExampleTests` and `SwiftUIHTMLExampleUITests` live next to the example project and keep the snapshot/test helpers, including `ViewSnapshotTester.swift`.
- `SwiftUIHTMLExampleTests/__Snapshots__/HTMLBasicTests` stores the PNG baselines and HTML payloads.
- `scripts/` hosts the snapshot-reporting helpers, OCR utilities, and the new `run_ios_snapshots.sh` driver.
- `mise.toml` defines high-level automation tasks invoked with `mise <task>` while `Package.swift` drives SwiftPM dependency resolution.

## Build, Test, and Development Commands
- `mise ios-snapshots`: boots the current iOS simulator, records every snapshot with `SWIFTUIHTML_SNAPSHOT_RECORD=1`, and produces `/tmp/swiftuihtml-ios-snapshot-report-*/index.html`.
- `mise ios-snapshot-single TEST_ONLY=...`: focuses on one XCTest and emits a mini report for that snapshot.
- `python3 scripts/snapshot_report.py --artifacts <dir> --baseline SwiftUIHTMLExampleTests/__Snapshots__/HTMLBasicTests --title "<label>" --out-prefix /tmp/...`: regenerates the HTML dashboard; add `--test-log` to include xcodebuild results.
- `xcodebuild test -scheme SwiftUIHTMLExample ...`: used when you need finer control, but prefer the `mise` wrapper for consistent artifact capture.

## Coding Style & Naming Conventions
- Follow Swift conventions: 4-space indentation, `camelCase` for variables/methods, `PascalCase` for types/protocols, and `lower_snake_case` for snapshot file stems (e.g., `testBulletImageAlignment.bulletImageAlignment.png`).
- Keep UI modifiers chained cleanly, avoid deeply nested closures, and prefer short helper functions (see `ViewSnapshotTester`).
- No automated formatter is enforced, but align new Swift files with the surrounding style and run `swift build`/`swift test` to surface formatter warnings.

## Testing Guidelines
- Snapshot tests live in `HTMLBasicTests`; each snapshot helper is also exposed through `HTMLBasicXCTest` so `xcodebuild -only-testing` can exercise the view.
- Naming follows `test<ScenarioDescription>`; the snapshot artifact includes the test name plus logic-specific suffixes (e.g., `.longWordsWithImages_byCharWrapping`).
- Always run through `mise ios-snapshots` (or the single/test-specific task) so artifacts, OCR logs, and HTML inputs are collected together with the report.

## Snapshot Reporting & Diagnostics
- `scripts/run_ios_snapshots.sh` now copies the simulator’s `artifactsRoot` back into `/tmp/swiftuihtml-ios-artifacts`, ensuring `snapshot_report.py` can find both baseline and new images.
- Diagnostic logs (`SWIFTUIHTML_ATTACHMENT_LOGS`, margin diagnostics, OCR json files) live under `/tmp/swiftuihtml-ios-artifacts` and are attached to XCTActivities. Link them from reports when investigating regressions.

## Commit & Pull Request Guidelines
- Write imperative commit messages (`Fix list-item gap`, `Align bullet-plus-image snapshot`). Include the test(s) you updated if relevant.
- PRs should describe what snapshot regressions exist, list which mise task(s) were run (e.g., `mise ios-snapshots`), and attach the latest report path (e.g., `/tmp/swiftuihtml-ios-snapshot-report-<timestamp>/index.html`). Add screenshots or report snippets when visual diffs matter.
123 changes: 97 additions & 26 deletions Documentation/BasicUsage.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct SimpleHTMLView: View {
"""

var body: some View {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
}
}
Expand Down Expand Up @@ -50,7 +50,7 @@ struct TextStyleExample: View {
"""

var body: some View {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
Expand All @@ -61,7 +61,56 @@ struct TextStyleExample: View {
}
```

## 3. 이미지 삽입 / Image Embedding
## 3. 루비 주석 / Ruby Annotations

### 한글 설명
`ruby`와 `rt` 태그를 사용해 일본어 루비 주석을 렌더링할 수 있습니다. `rt` 텍스트는 루비 문자열로 사용되고 `rp`/`rtc`는 무시됩니다. 필요하면 `ruby-position`, `ruby-scale`, `ruby-font-name`, `ruby-font-size`, `ruby-annotation-font-*` 속성으로 조정할 수 있습니다.

### English
You can render ruby annotations using `ruby` and `rt`. The `rt` text becomes the ruby string, and `rp`/`rtc` are ignored. Optional attributes include `ruby-position`, `ruby-scale`, `ruby-font-name`, `ruby-font-size`, and `ruby-annotation-font-*`.

```swift
struct RubyExample: View {
let html = """
<p>루비 주석 예제:</p>
<p>
<ruby>
漢字<rt>かんじ</rt>
</ruby>
를 읽습니다.
</p>
<p>
<ruby ruby-position="after" ruby-scale="0.5">
今日<rt>きょう</rt>
</ruby>
는 맑습니다.
</p>
<p>
<ruby ruby-font-size="22" ruby-annotation-font-size="12">
明日<rt>あした</rt>
</ruby>
도 맑습니다.
</p>
"""

var body: some View {
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
#if os(macOS)
let font = NSFont.systemFont(ofSize: 18)
#else
let font = UIFont.systemFont(ofSize: 18)
#endif
container.uiFont = font
return container
}())
}
}
```

## 4. 이미지 삽입 / Image Embedding

### 한글 설명
HTML 내에 이미지를 삽입하는 방법입니다. 웹 URL이나 로컬 이미지를 모두 지원합니다.
Expand All @@ -84,15 +133,15 @@ struct ImageExample: View {

var body: some View {
ScrollView {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.padding()
}
}
}
```

## 4. 링크 처리 / Link Handling
## 5. 링크 처리 / Link Handling

### 한글 설명
클릭 가능한 링크를 생성하는 방법입니다. 링크 태그는 자동으로 처리됩니다.
Expand All @@ -113,13 +162,13 @@ struct LinkExample: View {
"""

var body: some View {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
}
}
```

## 5. 블록 요소 구조 / Block Element Structure
## 6. 블록 요소 구조 / Block Element Structure

### 한글 설명
다양한 블록 요소들을 사용하는 방법입니다. div, p, section 등의 기본 블록 태그를 활용합니다.
Expand All @@ -146,14 +195,14 @@ struct BlockElementExample: View {
"""

var body: some View {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.padding()
}
}
```

## 6. 헤더와 섹션 구조 / Headers and Section Structure
## 7. 헤더와 섹션 구조 / Headers and Section Structure

### 한글 설명
HTML 문서 구조를 만드는 방법입니다. header, main, section, footer 태그를 활용합니다.
Expand Down Expand Up @@ -189,15 +238,15 @@ struct DocumentStructureExample: View {

var body: some View {
ScrollView {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.padding()
}
}
}
```

## 7. 줄바꿈 처리 / Line Break Handling
## 8. 줄바꿈 처리 / Line Break Handling

### 한글 설명
텍스트 줄바꿈을 처리하는 방법입니다. br 태그와 줄바꿈 모드를 설정할 수 있습니다.
Expand Down Expand Up @@ -225,7 +274,7 @@ struct LineBreakExample: View {
var body: some View {
VStack(spacing: 20) {
// 단어 단위 줄바꿈
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
Expand All @@ -235,7 +284,7 @@ struct LineBreakExample: View {
.border(Color.blue)

// 문자 단위 줄바꿈
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
Expand All @@ -249,13 +298,13 @@ struct LineBreakExample: View {
}
```

## 8. 폰트 설정 / Font Configuration
## 9. 폰트 설정 / Font Configuration

### 한글 설명
폰트 크기와 스타일을 설정하는 방법입니다. UIFont를 사용하여 시스템 폰트나 커스텀 폰트를 적용할 수 있습니다.
폰트 크기와 스타일을 설정하는 방법입니다. iOS는 UIFont, macOS는 NSFont를 사용하여 시스템 폰트나 커스텀 폰트를 적용할 수 있습니다.

### English
How to configure font size and style. You can apply system fonts or custom fonts using UIFont.
How to configure font size and style. Use UIFont on iOS and NSFont on macOS to apply system or custom fonts.

```swift
struct FontExample: View {
Expand All @@ -270,22 +319,32 @@ struct FontExample: View {
var body: some View {
VStack(spacing: 20) {
// 기본 폰트 크기
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
container.uiFont = .systemFont(ofSize: 14)
#if os(macOS)
let font = NSFont.systemFont(ofSize: 14)
#else
let font = UIFont.systemFont(ofSize: 14)
#endif
container.uiFont = font
return container
}())

Divider()

// 큰 폰트 크기
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
container.uiFont = .systemFont(ofSize: 18)
#if os(macOS)
let font = NSFont.systemFont(ofSize: 18)
#else
let font = UIFont.systemFont(ofSize: 18)
#endif
container.uiFont = font
return container
}())
}
Expand All @@ -294,7 +353,7 @@ struct FontExample: View {
}
```

## 9. 줄 높이 설정 / Line Height Configuration
## 10. 줄 높이 설정 / Line Height Configuration

### 한글 설명
텍스트 줄 높이를 조정하는 방법입니다. 가독성을 높이기 위해 줄 간격을 설정할 수 있습니다.
Expand All @@ -315,23 +374,31 @@ struct LineHeightExample: View {
var body: some View {
VStack(spacing: 20) {
// 좁은 줄 간격
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
#if os(macOS)
let font = NSFont.systemFont(ofSize: 14)
#else
let font = UIFont.systemFont(ofSize: 14)
#endif
container.uiFont = font
container.textLine = .lineHeight(font: font, lineHeight: 18)
return container
}())
.border(Color.red)

// 넓은 줄 간격
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
#if os(macOS)
let font = NSFont.systemFont(ofSize: 14)
#else
let font = UIFont.systemFont(ofSize: 14)
#endif
container.uiFont = font
container.textLine = .lineHeight(font: font, lineHeight: 28)
return container
Expand All @@ -343,7 +410,7 @@ struct LineHeightExample: View {
}
```

## 10. 복합 예제 / Complex Example
## 11. 복합 예제 / Complex Example

### 한글 설명
여러 기능을 함께 사용하는 복합 예제입니다.
Expand Down Expand Up @@ -394,11 +461,15 @@ struct ComplexExample: View {

var body: some View {
ScrollView {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, .default)
.htmlEnvironment(\.styleContainer, {
var container = HTMLStyleContainer()
#if os(macOS)
let font = NSFont.systemFont(ofSize: 16)
#else
let font = UIFont.systemFont(ofSize: 16)
#endif
container.uiFont = font
container.textLine = .lineHeight(font: font, lineHeight: 24)
container.lineBreakMode = .byWordWrapping
Expand All @@ -408,4 +479,4 @@ struct ComplexExample: View {
}
}
}
```
```
18 changes: 16 additions & 2 deletions Documentation/CustomTags.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
SwiftUIHTML에서 커스텀 태그를 만들고 등록하는 방법을 소개합니다.
This guide introduces how to create and register custom tags in SwiftUIHTML.

> 참고: `ruby`는 기본 InlineAttachmentTag로 제공되며 별도 등록이 필요 없습니다.
> Note: `ruby` is built-in as an InlineAttachmentTag and does not need custom registration.

## 태그 타입 / Tag Types

### 한글 설명
Expand All @@ -17,6 +20,17 @@ SwiftUIHTML supports three types of tags:
- **InlineTag**: Inline text elements (span, strong, em, etc.)
- **InlineAttachmentTag**: Inline attachment elements (img, video, etc.)

### Built-in ruby example / 기본 ruby 예제

```swift
let html = """
<p>
<ruby>漢字<rt>かんじ</rt></ruby>
를 읽습니다.
</p>
"""
```

## 1. 커스텀 블록 태그 / Custom Block Tag

### 한글 설명
Expand Down Expand Up @@ -372,7 +386,7 @@ struct ContentView: View {

var body: some View {
ScrollView {
HTMLView(html: html, parser: HTMLFuziParser())
HTMLView(html: html, parser: HTMLSwiftSoupParser())
.htmlEnvironment(\.configuration, customConfiguration())
.padding()
}
Expand Down Expand Up @@ -403,4 +417,4 @@ struct ContentView: View {
- Custom tags can override default tags
- BlockTag must implement the View protocol
- InlineTag only applies styles; rendering is handled by the system
- InlineAttachmentTag creates views that are inserted inline
- InlineAttachmentTag creates views that are inserted inline
Loading