From 37ff4b3f7b81fe50479f1cab194954f425281a7f Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Tue, 10 Jan 2023 22:03:17 +0100 Subject: [PATCH 01/29] Make the storage manager public To make the environment for htmlkit work, the manager needs to be cached in the application storage. --- .../Environment/Storage/Manager.swift | 10 ++--- .../Framework/Rendering/Renderer.swift | 8 +++- Sources/HTMLKitVapor/Environment.swift | 25 +++++++++++ .../Extensions/Vapor+HTMLKit.swift | 43 ++++++++++++++----- ...Configuration.swift => Localization.swift} | 12 +++--- Sources/HTMLKitVapor/ViewRenderer.swift | 4 +- Tests/HTMLKitVaporTests/ProviderTests.swift | 4 +- 7 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 Sources/HTMLKitVapor/Environment.swift rename Sources/HTMLKitVapor/{LingoConfiguration.swift => Localization.swift} (80%) diff --git a/Sources/HTMLKit/Framework/Environment/Storage/Manager.swift b/Sources/HTMLKit/Framework/Environment/Storage/Manager.swift index 2a34b1ae..0927214b 100644 --- a/Sources/HTMLKit/Framework/Environment/Storage/Manager.swift +++ b/Sources/HTMLKit/Framework/Environment/Storage/Manager.swift @@ -1,19 +1,19 @@ import Foundation /// A type, that manages the environment storage -internal class Manager { +public class Manager { /// The storage of the environment - internal var storage: [AnyKeyPath: Any] + private var storage: [AnyKeyPath: Any] /// Initiates a manager - internal init() { + public init() { self.storage = [:] } /// Retrieves an item from storage by its path - internal func retrieve(for path: AnyKeyPath) -> Any? { + public func retrieve(for path: AnyKeyPath) -> Any? { if let value = self.storage[path] { return value @@ -23,7 +23,7 @@ internal class Manager { } /// Adds und updates an item to the storage - internal func upsert(_ value: T, for path: AnyKeyPath) { + public func upsert(_ value: T, for path: AnyKeyPath) { self.storage[path] = value } } diff --git a/Sources/HTMLKit/Framework/Rendering/Renderer.swift b/Sources/HTMLKit/Framework/Rendering/Renderer.swift index 568112cd..2b95d7d3 100644 --- a/Sources/HTMLKit/Framework/Rendering/Renderer.swift +++ b/Sources/HTMLKit/Framework/Rendering/Renderer.swift @@ -54,8 +54,12 @@ public class Renderer { self.lingo = lingo } - public func add(model: T) where T: Encodable { - manager.upsert(model, for: \T.self) + /// Initiates the renderer. + public init(lingo: Lingo? = nil, manager: Manager) { + + self.environment = Environment() + self.manager = manager + self.lingo = lingo } /// Renders a view diff --git a/Sources/HTMLKitVapor/Environment.swift b/Sources/HTMLKitVapor/Environment.swift new file mode 100644 index 00000000..9f890f5d --- /dev/null +++ b/Sources/HTMLKitVapor/Environment.swift @@ -0,0 +1,25 @@ +/* + Abstract: + The file contains the configuration for the environment. + */ + +import Foundation +import HTMLKit + +/// The environment +final public class Environment { + + /// The storage manager + internal var manager: Manager + + /// Initiates a environment + internal init() { + + self.manager = Manager() + } + + /// Adds an encodable object to the storage + public func add(object: T) where T: Encodable { + manager.upsert(object, for: \T.self) + } +} diff --git a/Sources/HTMLKitVapor/Extensions/Vapor+HTMLKit.swift b/Sources/HTMLKitVapor/Extensions/Vapor+HTMLKit.swift index 24d6f81b..78e83d00 100644 --- a/Sources/HTMLKitVapor/Extensions/Vapor+HTMLKit.swift +++ b/Sources/HTMLKitVapor/Extensions/Vapor+HTMLKit.swift @@ -16,36 +16,57 @@ extension Application { /// The vapor provider public struct HtmlKit { - internal struct LingoStorageKey: StorageKey { + internal struct LocalizationStorageKey: StorageKey { - public typealias Value = LingoConfiguration + public typealias Value = Localization + } + + internal struct EnvironmentStorageKey: StorageKey { + + public typealias Value = Environment } /// The view localization - public var lingo: LingoConfiguration { + public var localization: Localization { + + if let configuration = self.application.storage[LocalizationStorageKey.self] { + return configuration + } + + let configuration = Localization() - if let configuration = self.application.storage[LingoStorageKey.self] { + self.application.storage[LocalizationStorageKey.self] = configuration + + return configuration + } + + /// The view environment + public var environment: Environment { + + if let configuration = self.application.storage[EnvironmentStorageKey.self] { return configuration } - let configuration = LingoConfiguration() + let configuration = Environment() - self.application.storage[LingoStorageKey.self] = configuration + self.application.storage[EnvironmentStorageKey.self] = configuration return configuration } /// The view renderer internal var renderer: ViewRenderer { - return .init(eventLoop: self.application.eventLoopGroup.next(), lingo: lingo) + return .init(eventLoop: application.eventLoopGroup.next(), + localization: localization, + environment: environment) } /// The application dependency - public let application: Application + internal let application: Application /// Creates the provider public init(application: Application) { - + self.application = application } } @@ -55,6 +76,8 @@ extension Request { /// Access to the view renderer public var htmlkit: ViewRenderer { - return .init(eventLoop: self.eventLoop, lingo: self.application.htmlkit.lingo) + return .init(eventLoop: self.eventLoop, + localization: self.application.htmlkit.localization, + environment: self.application.htmlkit.environment) } } diff --git a/Sources/HTMLKitVapor/LingoConfiguration.swift b/Sources/HTMLKitVapor/Localization.swift similarity index 80% rename from Sources/HTMLKitVapor/LingoConfiguration.swift rename to Sources/HTMLKitVapor/Localization.swift index 12b864b7..38dd4a15 100644 --- a/Sources/HTMLKitVapor/LingoConfiguration.swift +++ b/Sources/HTMLKitVapor/Localization.swift @@ -1,13 +1,13 @@ /* Abstract: - The file contains the configuration for Lingo. + The file contains the configuration for the localization. */ import Foundation import Lingo /// The localization -public class LingoConfiguration { +public class Localization { /// A enumeration of possible locale identifier public enum Locale: String { @@ -23,10 +23,10 @@ public class LingoConfiguration { case indonesian = "id" } - /// The root path + /// The path of the source directory internal var defaultDirectory: String - /// The locale indentifier + /// The default locale indentifier internal var defaultLocale: String internal var lingo: Lingo? { @@ -41,8 +41,8 @@ public class LingoConfiguration { } /// Sets the root path - public func set(directory: URL) { - self.defaultDirectory = directory.path + public func set(source: URL) { + self.defaultDirectory = source.path } /// Sets the default locale indentifier diff --git a/Sources/HTMLKitVapor/ViewRenderer.swift b/Sources/HTMLKitVapor/ViewRenderer.swift index c583284d..90344549 100644 --- a/Sources/HTMLKitVapor/ViewRenderer.swift +++ b/Sources/HTMLKitVapor/ViewRenderer.swift @@ -17,10 +17,10 @@ public class ViewRenderer { internal var renderer: Renderer /// Creates the view renderer - public init(eventLoop: EventLoop, lingo: LingoConfiguration) { + public init(eventLoop: EventLoop, localization: Localization, environment: Environment) { self.eventLoop = eventLoop - self.renderer = Renderer(lingo: lingo.lingo) + self.renderer = Renderer(lingo: localization.lingo, manager: environment.manager) } /// Renders a layout and its context diff --git a/Tests/HTMLKitVaporTests/ProviderTests.swift b/Tests/HTMLKitVaporTests/ProviderTests.swift index 69974f31..82aa6c20 100644 --- a/Tests/HTMLKitVaporTests/ProviderTests.swift +++ b/Tests/HTMLKitVaporTests/ProviderTests.swift @@ -157,8 +157,8 @@ final class ProviderTests: XCTestCase { defer { app.shutdown() } - app.htmlkit.lingo.set(directory: currentDirectory) - app.htmlkit.lingo.set(locale: .french) + app.htmlkit.localization.set(source: currentDirectory) + app.htmlkit.localization.set(locale: .french) app.get("test") { request async throws -> Vapor.View in From 6024de2aee5b29b10f45e707124b2d529475a274 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 14 Jan 2023 21:21:42 +0100 Subject: [PATCH 02/29] Add the press modifier to the text component --- Sources/HTMLKitComponents/Components/Text.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Sources/HTMLKitComponents/Components/Text.swift b/Sources/HTMLKitComponents/Components/Text.swift index 285ca745..a3293e03 100644 --- a/Sources/HTMLKitComponents/Components/Text.swift +++ b/Sources/HTMLKitComponents/Components/Text.swift @@ -65,6 +65,21 @@ extension Text: HoverModifier { } } +extension Text: PressModifier { + + public func onClick(perfom action: Actions) -> Text { + return self.mutate(clickevent: action.script) + } + + public func onTap(perfom action: Actions) -> Text { + return self.mutate(tapevent: action.script) + } + + public func onPress(perfom action: Actions) -> Text { + return self.mutate(pressevent: action.script) + } +} + extension Text: TextModifier { public func font(_ style: Tokens.TextStyle) -> Text { From 38947f6a802110aea6735a6d3099475f66a334a2 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 15 Jan 2023 14:22:27 +0100 Subject: [PATCH 03/29] Add the environment value to the content rendering In a specific case the environment value didn't get caught by the renderer. --- Sources/HTMLKit/Framework/Rendering/Renderer.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/HTMLKit/Framework/Rendering/Renderer.swift b/Sources/HTMLKit/Framework/Rendering/Renderer.swift index 2b95d7d3..9e769183 100644 --- a/Sources/HTMLKit/Framework/Rendering/Renderer.swift +++ b/Sources/HTMLKit/Framework/Rendering/Renderer.swift @@ -116,6 +116,10 @@ public class Renderer { result += try render(modifier: modifier) } + if let value = content as? EnvironmentValue { + result += try render(value: value) + } + if let element = content as? String { result += element } From 3d5e4b24b61fe75f1740cb73762cc726b19552dd Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 15 Jan 2023 14:23:32 +0100 Subject: [PATCH 04/29] Fix the styling of the divider component --- Sources/HTMLKitComponents/Resources/css/divider.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/HTMLKitComponents/Resources/css/divider.css b/Sources/HTMLKitComponents/Resources/css/divider.css index a5a96d63..eb697050 100644 --- a/Sources/HTMLKitComponents/Resources/css/divider.css +++ b/Sources/HTMLKitComponents/Resources/css/divider.css @@ -7,5 +7,7 @@ margin-top: 5px; margin-bottom: 5px; width: 100%; + height: 1px; + border: 0; background-color: var(--dividerColor); } From 49b2139f5f2257ec5b090f8d89b7c7ed75179499 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 15 Jan 2023 15:01:13 +0100 Subject: [PATCH 05/29] Add a dropdown component --- .../Components/Dropdown.swift | 37 +++++++++++++++++++ .../Resources/css/dropdown.css | 33 +++++++++++++++++ .../HTMLKitComponents/Resources/css/roots.css | 15 ++++++-- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 Sources/HTMLKitComponents/Components/Dropdown.swift create mode 100644 Sources/HTMLKitComponents/Resources/css/dropdown.css diff --git a/Sources/HTMLKitComponents/Components/Dropdown.swift b/Sources/HTMLKitComponents/Components/Dropdown.swift new file mode 100644 index 00000000..5c3dbd37 --- /dev/null +++ b/Sources/HTMLKitComponents/Components/Dropdown.swift @@ -0,0 +1,37 @@ +/* + Abstract: + The file contains a dropdown component. + */ + +import HTMLKit + +public struct Dropdown: View { + + internal var label: [Content] + + internal var content: [Content] + + internal var classes: [String] + + public init(@ContentBuilder content: () -> [Content], @ContentBuilder label: () -> [Content]) { + + self.label = label() + self.content = content() + self.classes = ["dropdown"] + } + + public var body: Content { + Division { + Division { + label + } + .class("dropdown-label") + Division { + content + } + .class("dropdown-content") + } + .class(classes.joined(separator: " ")) + .tabIndex(1) + } +} diff --git a/Sources/HTMLKitComponents/Resources/css/dropdown.css b/Sources/HTMLKitComponents/Resources/css/dropdown.css new file mode 100644 index 00000000..d548744c --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/css/dropdown.css @@ -0,0 +1,33 @@ +.dropdown { + display: inline-block; + position: relative; + cursor: pointer; + outline: none; +} + +.dropdown-label { + display: inline-block; +} + +.dropdown .dropdown-content { + display: none; + position: absolute; + padding: 6px 0px; + width: 200px; + border: 1px solid var(--dropdownBorderColor); + border-radius: var(--dropdownBorderRadius); + background-color: var(--dropdownBackgroundColor); + z-index: 1; +} + +.dropdown:focus .dropdown-content { + display: inline-block; +} + +.dropdown .list .list-row:hover { + background-color: var(--dropdownHoverColor); +} + +.dropdown .list .list-row .link { + display: block; +} diff --git a/Sources/HTMLKitComponents/Resources/css/roots.css b/Sources/HTMLKitComponents/Resources/css/roots.css index 76b53d9c..4d6bdcd2 100644 --- a/Sources/HTMLKitComponents/Resources/css/roots.css +++ b/Sources/HTMLKitComponents/Resources/css/roots.css @@ -138,7 +138,7 @@ divider variables */ - --dividerColor: #FFFFFF; + --dividerColor: var(--grayColor); /** button variables @@ -178,13 +178,22 @@ /** - grid variables + card variables */ --cardPaddingY: 12px; --cardPaddingX: 16px; --cardBorderWidth: 1px; - --cardBorderRadius: 15px; + --cardBorderRadius: 5px; --cardBorderColor: var(--grayColor); --cardBackgroundColor: var(--whiteColor); + + /** + dropdown variables + */ + + --dropdownBorderRadius: 5px; + --dropdownBorderColor: var(--grayColor); + --dropdownHoverColor: var(--silverColor); + --dropdownBackgroundColor: var(--whiteColor); } From a230ae6a123dce562c938c7882819f2dd0a068f0 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 23 Jan 2023 20:25:04 +0100 Subject: [PATCH 06/29] Revise the card component --- .../HTMLKitComponents/Components/Card.swift | 24 +++++++++++--- .../HTMLKitComponents/Resources/css/card.css | 31 ++++++++++++++++--- .../HTMLKitComponents/Resources/css/roots.css | 2 ++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Card.swift b/Sources/HTMLKitComponents/Components/Card.swift index 2f73d355..62a3ec4d 100644 --- a/Sources/HTMLKitComponents/Components/Card.swift +++ b/Sources/HTMLKitComponents/Components/Card.swift @@ -1,8 +1,9 @@ import HTMLKit -public struct Card: View, Modifiable { +public class Card: View { - internal var content: [Content] + public var header: [Content]? + public var content: [Content] internal var classes: [String] @@ -12,10 +13,25 @@ public struct Card: View, Modifiable { self.classes = ["card"] } + public init(@ContentBuilder content: () -> [Content], + @ContentBuilder header: () -> [Content]) { + + self.content = content() + self.header = header() + self.classes = ["card"] + } + public var body: Content { Division { - content + Division { + header + } + .class("card-header") + Division { + content + } + .class("card-body") } - .class(self.classes.joined(separator: " ")) + .class(classes.joined(separator: " ")) } } diff --git a/Sources/HTMLKitComponents/Resources/css/card.css b/Sources/HTMLKitComponents/Resources/css/card.css index cf5ead72..193bca4d 100644 --- a/Sources/HTMLKitComponents/Resources/css/card.css +++ b/Sources/HTMLKitComponents/Resources/css/card.css @@ -3,13 +3,36 @@ */ .card { - padding-top: var(--cardPaddingY); - padding-right: var(--cardPaddingX); - padding-bottom: var(--cardPaddingY); - padding-left: var(--cardPaddingX); + + display: flex; + flex-direction: column; border-width: var(--cardBorderWidth); border-style: solid; border-radius: var(--cardBorderRadius); border-color: var(--cardBorderColor); background-color: var(--cardBackgroundColor); } + +.card .card-header { + + max-height: var(--cardHeaderHight); + border-top-left-radius: inherit; + border-top-right-radius: inherit; + background-color: var(--cardHeaderBackgroundColor); + overflow: hidden; +} + +.card .card-header .image { + + border-radius: inherit; +} + +.card .card-body { + + padding-top: var(--cardPaddingY); + padding-right: var(--cardPaddingX); + padding-bottom: var(--cardPaddingY); + padding-left: var(--cardPaddingX); + border-bottom-left-radius: inherit; + border-bottom-right-radius: inherit; +} diff --git a/Sources/HTMLKitComponents/Resources/css/roots.css b/Sources/HTMLKitComponents/Resources/css/roots.css index 4d6bdcd2..dc38c8d6 100644 --- a/Sources/HTMLKitComponents/Resources/css/roots.css +++ b/Sources/HTMLKitComponents/Resources/css/roots.css @@ -187,6 +187,8 @@ --cardBorderRadius: 5px; --cardBorderColor: var(--grayColor); --cardBackgroundColor: var(--whiteColor); + --cardHeaderHight: 200px; + --cardHeaderBackgroundColor: var(--whiteColor); /** dropdown variables From ae30808bcd0c916c09d64fbb27c21e7291fde2d3 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 23 Jan 2023 20:34:47 +0100 Subject: [PATCH 07/29] Remove the css from the grid item The grid should only be for alignment. --- Sources/HTMLKitComponents/Resources/css/grid.css | 9 --------- Sources/HTMLKitComponents/Resources/css/roots.css | 7 ------- Sources/HTMLKitComponents/Tokens.swift | 2 ++ 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/Sources/HTMLKitComponents/Resources/css/grid.css b/Sources/HTMLKitComponents/Resources/css/grid.css index ab57661b..a6e59705 100644 --- a/Sources/HTMLKitComponents/Resources/css/grid.css +++ b/Sources/HTMLKitComponents/Resources/css/grid.css @@ -10,15 +10,6 @@ .grid-item { - padding-top: var(--gridItemPaddingY); - padding-right: var(--gridItemPaddingX); - padding-bottom: var(--gridItemPaddingY); - padding-left: var(--gridItemPaddingX); - border-width: var(--gridItemBorderWidth); - border-style: solid; - border-color: var(--gridItemBorderColor); - border-radius: var(--gridItemBorderRadius); - overflow: hidden; } diff --git a/Sources/HTMLKitComponents/Resources/css/roots.css b/Sources/HTMLKitComponents/Resources/css/roots.css index dc38c8d6..8974b85e 100644 --- a/Sources/HTMLKitComponents/Resources/css/roots.css +++ b/Sources/HTMLKitComponents/Resources/css/roots.css @@ -169,13 +169,6 @@ */ --gridGapSize: 15px; - --gridItemPaddingY: 12px; - --gridItemPaddingX: 16px; - --gridItemBorderWidth: 1px; - --gridItemBorderColor: var(--grayColor); - --gridItemBorderRadius: 5px; - --gridItemBackgroundColor: var(--whiteColor); - /** card variables diff --git a/Sources/HTMLKitComponents/Tokens.swift b/Sources/HTMLKitComponents/Tokens.swift index 6cdfe061..0f4ff674 100644 --- a/Sources/HTMLKitComponents/Tokens.swift +++ b/Sources/HTMLKitComponents/Tokens.swift @@ -468,6 +468,8 @@ public enum Tokens { case quarter = "ratio:25" case third = "ratio:33" case half = "ratio:50" + case fifth = "ratio:20" + case sixth = "ratio:15" } /// A style for a list. From 8b925debba1586e2a1a4ea6f26e38d4f1fd3688d Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 30 Jan 2023 20:47:42 +0100 Subject: [PATCH 08/29] Add a scrollview component --- .../Components/ScrollView.swift | 26 +++++++++++++++++ .../HTMLKitComponents/Resources/css/roots.css | 7 +++++ .../Resources/css/scrollview.css | 29 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 Sources/HTMLKitComponents/Components/ScrollView.swift create mode 100644 Sources/HTMLKitComponents/Resources/css/scrollview.css diff --git a/Sources/HTMLKitComponents/Components/ScrollView.swift b/Sources/HTMLKitComponents/Components/ScrollView.swift new file mode 100644 index 00000000..5198405f --- /dev/null +++ b/Sources/HTMLKitComponents/Components/ScrollView.swift @@ -0,0 +1,26 @@ +/* + Abstract: + The file contains everything related to the scrollview component. + */ + +import HTMLKit + +public struct ScrollView: View { + + internal var content: [Content] + + internal var classes: [String] + + public init(direction: Tokens.FlowDirection, @ContentBuilder content: () -> [Content]) { + + self.content = content() + self.classes = ["scrollview", direction.rawValue] + } + + public var body: Content { + Division { + content + } + .class(classes.joined(separator: " ")) + } +} diff --git a/Sources/HTMLKitComponents/Resources/css/roots.css b/Sources/HTMLKitComponents/Resources/css/roots.css index 8974b85e..f78e1a04 100644 --- a/Sources/HTMLKitComponents/Resources/css/roots.css +++ b/Sources/HTMLKitComponents/Resources/css/roots.css @@ -191,4 +191,11 @@ --dropdownBorderColor: var(--grayColor); --dropdownHoverColor: var(--silverColor); --dropdownBackgroundColor: var(--whiteColor); + + /** + scrollview variables + */ + + --scrollViewGapSize: 25px; + --scrollViewBackgroundColor: transparent; } diff --git a/Sources/HTMLKitComponents/Resources/css/scrollview.css b/Sources/HTMLKitComponents/Resources/css/scrollview.css new file mode 100644 index 00000000..a5e22ad6 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/css/scrollview.css @@ -0,0 +1,29 @@ +/** + scrollview component + */ + +.scrollview { + display: grid; + gap: var(--scrollViewGapSize); + background-color: var(--scrollViewBackgroundColor); +} + +.scrollview::-webkit-scrollbar{ + display: none; +} + +.scrollview.direction\:horizontal { + grid-auto-flow: column; + grid-auto-columns: min-content; + height: inherit; + overflow-x: auto; + overscroll-behavior-inline: contain; +} + +.scrollview.direction\:vertical { + grid-auto-flow: row; + grid-auto-rows: min-content; + height: inherit; + overflow-y: auto; + overscroll-behavior-y: contain; +} From cacee4334595c8a95c805bee2f8e063188e0d75e Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 30 Jan 2023 22:09:10 +0100 Subject: [PATCH 09/29] Add a carousel component --- .../Components/Carousel.swift | 50 +++++++++++++++++ .../Resources/css/carousel.css | 53 +++++++++++++++++++ .../HTMLKitComponents/Resources/css/roots.css | 11 ++++ 3 files changed, 114 insertions(+) create mode 100644 Sources/HTMLKitComponents/Components/Carousel.swift create mode 100644 Sources/HTMLKitComponents/Resources/css/carousel.css diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift new file mode 100644 index 00000000..29d1759a --- /dev/null +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -0,0 +1,50 @@ +/* + Abstract: + The file contains everything related to the carousel component. + */ + +import HTMLKit + +public struct Carousel: View { + + public var indication: [Content] + + public var content: [Content] + + public init(@ContentBuilder content: () -> [Content], + @ContentBuilder indication: () -> [Content]) { + + self.content = content() + self.indication = indication() + } + + public var body: Content { + Division { + Division { + content + } + .class("carousel-content") + Division { + indication + } + .class("carousel-indication") + } + .class("carousel") + } +} + +public struct Indicator: View { + + public var id: String + + public init(id: String) { + self.id = id + } + + public var body: Content { + Anchor { + } + .reference(id) + .class("indicator") + } +} diff --git a/Sources/HTMLKitComponents/Resources/css/carousel.css b/Sources/HTMLKitComponents/Resources/css/carousel.css new file mode 100644 index 00000000..2f54172d --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/css/carousel.css @@ -0,0 +1,53 @@ +/** + carousel component + */ + +.carousel { + + display: flex; + flex-direction: column; + width: 100%; + height: 400px; +} + +.carousel-content { + + display: grid; + grid-auto-flow: column; + grid-auto-columns: 100%; + height: 350px; + border: var(--carouselBorderWidth) solid var(--carouselBorderColor); + border-radius: var(--carourselBorderRadius); + background-color: var(--carouselBackgroundColor); + overflow-x: auto; + scroll-behavior: smooth; + scroll-snap-type: x mandatory; + overscroll-behavior-inline: contain; +} + +.carousel-content::-webkit-scrollbar{ + display: none; +} + +.carousel-content .image { + scroll-snap-align: start; + scroll-snap-stop: normal; +} + +.carousel-indication { + + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + height: 50px; +} + +.indicator { + + width: 40px; + height: 6px; + border: 1px solid var(--indicatorBorderColor); + border-radius: var(--indicatorBorderRadius); + background-color: var(--indicatorBackgroundColor); +} diff --git a/Sources/HTMLKitComponents/Resources/css/roots.css b/Sources/HTMLKitComponents/Resources/css/roots.css index f78e1a04..299469a0 100644 --- a/Sources/HTMLKitComponents/Resources/css/roots.css +++ b/Sources/HTMLKitComponents/Resources/css/roots.css @@ -198,4 +198,15 @@ --scrollViewGapSize: 25px; --scrollViewBackgroundColor: transparent; + + /** + carousel variables + */ + --carouselBorderWidth: 1px; + --carouselBorderColor: #000000; + --carouselBorderRadius: 10px; + --carouselBackgroundColor: transparent; + --indicatorBorderRadius: 5px; + --indicatorBackgroundColor: transparent; + --indicatorBorderColor: #000000; } From 2ab2d83610d36e5fccc02957833cb2039177183d Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 4 Feb 2023 14:21:25 +0100 Subject: [PATCH 10/29] Extend the carousel component --- .../Components/Carousel.swift | 77 +++++++++++++++++-- .../Resources/css/carousel.css | 45 +++++++++-- 2 files changed, 107 insertions(+), 15 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift index 29d1759a..420e2243 100644 --- a/Sources/HTMLKitComponents/Components/Carousel.swift +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -7,15 +7,25 @@ import HTMLKit public struct Carousel: View { - public var indication: [Content] + internal var indication: [Content] - public var content: [Content] + internal var content: [Content] + + internal var classes: [String] public init(@ContentBuilder content: () -> [Content], @ContentBuilder indication: () -> [Content]) { self.content = content() self.indication = indication() + self.classes = ["carousel"] + } + + internal init(indication: [Content], content: [Content], classes: [String]) { + + self.indication = indication + self.content = content + self.classes = classes } public var body: Content { @@ -29,22 +39,75 @@ public struct Carousel: View { } .class("carousel-indication") } - .class("carousel") + .class(classes.joined(separator: " ")) } } -public struct Indicator: View { +public struct Slide: View, Identifiable, Modifiable { - public var id: String + internal var id: String? - public init(id: String) { + internal var source: String + + internal var classes: [String] + + internal var caption: [Content] + + public init(source: String, @ContentBuilder caption: () -> [Content]) { + + self.source = source + self.caption = caption() + self.classes = ["slide"] + } + + internal init(id: String?, source: String, caption: [Content], classes: [String]) { + self.id = id + self.source = source + self.caption = caption + self.classes = classes + } + + public var body: Content { + Division { + Division { + HTMLKit.Image() + .source(source) + } + .class("slide-thumbnail") + Division { + caption + } + .class("slide-caption") + } + .class(classes.joined(separator: " ")) + .modify(unwrap: id) { + $0.id($1) + } + } + + public func tag(_ value: String) -> Slide { + return self.mutate(id: value) + } +} + +public struct Indicator: View { + + internal var tag: String + + public init(for tag: String) { + self.tag = "#" + tag + } + + internal init(tag: String) { + self.tag = tag } public var body: Content { Anchor { } - .reference(id) + .reference(tag) .class("indicator") } } + diff --git a/Sources/HTMLKitComponents/Resources/css/carousel.css b/Sources/HTMLKitComponents/Resources/css/carousel.css index 2f54172d..eb3ce286 100644 --- a/Sources/HTMLKitComponents/Resources/css/carousel.css +++ b/Sources/HTMLKitComponents/Resources/css/carousel.css @@ -3,7 +3,6 @@ */ .carousel { - display: flex; flex-direction: column; width: 100%; @@ -11,13 +10,14 @@ } .carousel-content { - display: grid; grid-auto-flow: column; grid-auto-columns: 100%; height: 350px; - border: var(--carouselBorderWidth) solid var(--carouselBorderColor); - border-radius: var(--carourselBorderRadius); + border-width: var(--carouselBorderWidth); + border-style: solid; + border-color: var(--carouselBorderColor); + border-radius: var(--carouselBorderRadius); background-color: var(--carouselBackgroundColor); overflow-x: auto; scroll-behavior: smooth; @@ -29,13 +29,31 @@ display: none; } -.carousel-content .image { +.slide { + display: flex; + height: auto; scroll-snap-align: start; scroll-snap-stop: normal; + overflow: hidden; +} + +.slide-thumbnail { + width: 60%; +} + +.slide-thumbnail > img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.slide-caption { + width: 40%; + padding-block: 24px; + padding-inline: 24px; } .carousel-indication { - display: flex; align-items: center; justify-content: center; @@ -44,10 +62,21 @@ } .indicator { - width: 40px; height: 6px; - border: 1px solid var(--indicatorBorderColor); + border-width: 1px; + border-style: solid; + border-color: var(--indicatorBorderColor); border-radius: var(--indicatorBorderRadius); background-color: var(--indicatorBackgroundColor); } + +.indicator.active { + border-color: var(--primaryColor); + background-color: var(--primaryColor); +} + +.indicator:hover { + border-color: var(--primaryColor); + background-color: var(--primaryColor); +} From c1b2e138b3b0a62f22aedbe2911c3464adfb6995 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 4 Feb 2023 16:09:15 +0100 Subject: [PATCH 11/29] Add more component tests --- .../ComponentTests.swift | 133 ++++++++++++++++-- 1 file changed, 123 insertions(+), 10 deletions(-) diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index 68578b5a..e61878b7 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -83,10 +83,10 @@ final class ComponentTests: XCTestCase { ) } - func testFormContainer() throws { + func testForm() throws { let view = TestView { - HTMLKitComponents.Form(method: .post) { + Form(method: .post) { } } @@ -205,6 +205,21 @@ final class ComponentTests: XCTestCase { ) } + func testSelectField() throws { + + let view = TestView { + SelectField(name: "name") { + } + } + + XCTAssertEqual(try renderer.render(view: view), + """ + + """ + ) + } + func testImage() throws { let view = TestView { @@ -252,13 +267,13 @@ final class ComponentTests: XCTestCase { let view = TestView { Link(destination: "uri") { - "link" + "Link" } } XCTAssertEqual(try renderer.render(view: view), """ - link + Link """ ) } @@ -324,16 +339,13 @@ final class ComponentTests: XCTestCase { let view = TestView { Text { + "Text" } - .fontSize(.large) - .fontTransformation(.uppercase) - .foregroundColor(.blue) - .bold() } XCTAssertEqual(try renderer.render(view: view), """ -

+

Text

""" ) } @@ -400,7 +412,108 @@ final class ComponentTests: XCTestCase { XCTAssertEqual(try renderer.render(view: view), """ -
+
\ +
\ +
\ +
+ """ + ) + } + + func testCarousel() throws { + + let view = TestView { + Carousel { + } indication: { + } + } + + XCTAssertEqual(try renderer.render(view: view), + """ + + """ + ) + } + + func testSlide() throws { + + let view = TestView { + Slide(source: "#") { + } + } + + XCTAssertEqual(try renderer.render(view: view), + """ +
\ +
\ + \ +
\ +
\ +
+ """ + ) + } + + func testIndicator() throws { + + let view = TestView { + Indicator(for: "example") + } + + XCTAssertEqual(try renderer.render(view: view), + """ + + """ + ) + } + + func testDropdown() throws { + + let view = TestView { + Dropdown { + } label: { + } + + } + + XCTAssertEqual(try renderer.render(view: view), + """ + + """ + ) + } + + func testModal() throws { + + let view = TestView { + Modal { + } + } + + XCTAssertEqual(try renderer.render(view: view), + """ + + """ + ) + } + + func testScrollView() throws { + + let view = TestView { + ScrollView(direction: .horizontal) { + } + } + + XCTAssertEqual(try renderer.render(view: view), + """ +
""" ) } From efc5b5216e7b1e114cbe0f638e6f710c5124a6ea Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 4 Feb 2023 16:20:14 +0100 Subject: [PATCH 12/29] Fix test failing --- Tests/HTMLKitComponentsTests/ComponentTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index e61878b7..01b71c30 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -345,7 +345,7 @@ final class ComponentTests: XCTestCase { XCTAssertEqual(try renderer.render(view: view), """ -

Text

+

Text

""" ) } From c1a9f386fbd765241ec3aabaf14b08d41bab836a Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Thu, 9 Feb 2023 20:06:32 +0100 Subject: [PATCH 13/29] Add motion to the carousel by adding javascript --- .../Components/Carousel.swift | 12 ++-- .../Resources/css/carousel.css | 2 +- .../Resources/js/carousel.js | 63 +++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 Sources/HTMLKitComponents/Resources/js/carousel.js diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift index 420e2243..d1511bf1 100644 --- a/Sources/HTMLKitComponents/Components/Carousel.swift +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -40,6 +40,9 @@ public struct Carousel: View { .class("carousel-indication") } .class(classes.joined(separator: " ")) + Script { + "new Carousel();" + } } } @@ -95,19 +98,14 @@ public struct Indicator: View { internal var tag: String - public init(for tag: String) { - self.tag = "#" + tag - } - - internal init(tag: String) { + public init(tag: String) { self.tag = tag } public var body: Content { Anchor { } - .reference(tag) .class("indicator") + .reference(tag) } } - diff --git a/Sources/HTMLKitComponents/Resources/css/carousel.css b/Sources/HTMLKitComponents/Resources/css/carousel.css index eb3ce286..c9c1c48f 100644 --- a/Sources/HTMLKitComponents/Resources/css/carousel.css +++ b/Sources/HTMLKitComponents/Resources/css/carousel.css @@ -71,7 +71,7 @@ background-color: var(--indicatorBackgroundColor); } -.indicator.active { +.indicator.state\:active { border-color: var(--primaryColor); background-color: var(--primaryColor); } diff --git a/Sources/HTMLKitComponents/Resources/js/carousel.js b/Sources/HTMLKitComponents/Resources/js/carousel.js new file mode 100644 index 00000000..862ea0eb --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/js/carousel.js @@ -0,0 +1,63 @@ +var Carousel = (function () { + + 'use strict'; + + function Self(element) { + + this.element = document.getElementsByClassName('carousel-content')[0]; + this.slides = document.getElementsByClassName('slide'); + this.indicators = document.getElementsByClassName('indicator'); + + this.toggleState(0); + + this.initiateListener(); + } + + Self.prototype.initiateListener = function () { + + var self = this; + + for (let indicator of this.indicators) { + + indicator.addEventListener('click', function (event) { + + event.preventDefault(); + + self.slideTo(self.getPosition(event.target.getAttribute('href'))); + }); + } + }; + + Self.prototype.getPosition = function (name) { + + for(var position = 0; position < this.slides.length; position++) { + + if (this.slides[position].id == name) { + return position; + } + } + }; + + Self.prototype.toggleState = function (position) { + + for(let indicator of this.indicators) { + indicator.classList.remove('state:active'); + } + + this.indicators[position].classList.add('state:active'); + }; + + Self.prototype.slideTo = function (position) { + + var self = this; + + this.element.scrollTo({ + left: (position * this.slides[position].offsetWidth) + }); + + self.toggleState(position); + }; + + return Self; + +})(); From 947a904839a9884f5e7e9b09ff6e45432f890ec9 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Thu, 9 Feb 2023 21:03:01 +0100 Subject: [PATCH 14/29] Add autoplay to the carousel --- .../Resources/css/carousel.css | 8 ++----- .../Resources/js/carousel.js | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Sources/HTMLKitComponents/Resources/css/carousel.css b/Sources/HTMLKitComponents/Resources/css/carousel.css index c9c1c48f..c0923cdd 100644 --- a/Sources/HTMLKitComponents/Resources/css/carousel.css +++ b/Sources/HTMLKitComponents/Resources/css/carousel.css @@ -19,10 +19,7 @@ border-color: var(--carouselBorderColor); border-radius: var(--carouselBorderRadius); background-color: var(--carouselBackgroundColor); - overflow-x: auto; - scroll-behavior: smooth; - scroll-snap-type: x mandatory; - overscroll-behavior-inline: contain; + overflow: hidden; } .carousel-content::-webkit-scrollbar{ @@ -32,8 +29,6 @@ .slide { display: flex; height: auto; - scroll-snap-align: start; - scroll-snap-stop: normal; overflow: hidden; } @@ -69,6 +64,7 @@ border-color: var(--indicatorBorderColor); border-radius: var(--indicatorBorderRadius); background-color: var(--indicatorBackgroundColor); + cursor: pointer; } .indicator.state\:active { diff --git a/Sources/HTMLKitComponents/Resources/js/carousel.js b/Sources/HTMLKitComponents/Resources/js/carousel.js index 862ea0eb..4a58fca7 100644 --- a/Sources/HTMLKitComponents/Resources/js/carousel.js +++ b/Sources/HTMLKitComponents/Resources/js/carousel.js @@ -10,6 +10,8 @@ var Carousel = (function () { this.toggleState(0); + this.initiateAutoplay(1); + this.initiateListener(); } @@ -28,6 +30,25 @@ var Carousel = (function () { } }; + Self.prototype.initiateAutoplay = function (position) { + + var self = this; + + setInterval(function() { + + if (position < self.slides.length) { + + self.slideTo(position); + + position += 1; + + } else { + position = 0; + } + + }, 7000); + } + Self.prototype.getPosition = function (name) { for(var position = 0; position < this.slides.length; position++) { From 519927a1f63c111e60e6b247f5351f1501940bc6 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Thu, 9 Feb 2023 21:21:46 +0100 Subject: [PATCH 15/29] Fix tests --- Sources/HTMLKitComponents/Components/Carousel.swift | 4 ++-- Sources/HTMLKitComponents/Resources/js/carousel.js | 2 +- Tests/HTMLKitComponentsTests/ComponentTests.swift | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift index d1511bf1..a22225ad 100644 --- a/Sources/HTMLKitComponents/Components/Carousel.swift +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -98,8 +98,8 @@ public struct Indicator: View { internal var tag: String - public init(tag: String) { - self.tag = tag + public init(for tag: String) { + self.tag = "#" + tag } public var body: Content { diff --git a/Sources/HTMLKitComponents/Resources/js/carousel.js b/Sources/HTMLKitComponents/Resources/js/carousel.js index 4a58fca7..602fd37b 100644 --- a/Sources/HTMLKitComponents/Resources/js/carousel.js +++ b/Sources/HTMLKitComponents/Resources/js/carousel.js @@ -25,7 +25,7 @@ var Carousel = (function () { event.preventDefault(); - self.slideTo(self.getPosition(event.target.getAttribute('href'))); + self.slideTo(self.getPosition(event.target.getAttribute('href').replace('#', ''))); }); } }; diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index 01b71c30..84de8f1b 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -433,7 +433,10 @@ final class ComponentTests: XCTestCase { + \ + """ ) } @@ -465,7 +468,7 @@ final class ComponentTests: XCTestCase { XCTAssertEqual(try renderer.render(view: view), """ - + """ ) } From 50da4a9f700fc09ab771a4624c1522e4ea7de165 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 12 Feb 2023 13:51:21 +0100 Subject: [PATCH 16/29] Add a test for the symbol component --- .../ComponentTests.swift | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index 84de8f1b..41827e26 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -520,4 +520,26 @@ final class ComponentTests: XCTestCase { """ ) } + + func testSymbol() throws { + + let view = TestView { + Symbol(system: "folder") + } + + XCTAssertEqual(try renderer.render(view: view), + """ + \ + \ + \ + \ + \ + \ + \ + \ + \ + + """ + ) + } } From 1dc382e7a9ec8285297d06c2f20d55bbd940b624 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Tue, 14 Feb 2023 20:21:10 +0100 Subject: [PATCH 17/29] Add the possibility to disable views --- .../HTMLKitComponents/Components/Button.swift | 18 +++++ .../HTMLKitComponents/Components/Form.swift | 72 +++++++++++++++++++ .../Modifiers/ButtonModifier.swift | 7 ++ .../Modifiers/InputModifier.swift | 7 ++ .../Resources/css/carousel.css | 5 -- .../HTMLKitComponents/Resources/css/utils.css | 9 +++ Sources/HTMLKitComponents/Tokens.swift | 7 ++ 7 files changed, 120 insertions(+), 5 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Button.swift b/Sources/HTMLKitComponents/Components/Button.swift index c42f56a7..5a771bf3 100644 --- a/Sources/HTMLKitComponents/Components/Button.swift +++ b/Sources/HTMLKitComponents/Components/Button.swift @@ -77,6 +77,15 @@ extension Button: ButtonModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> Button { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> Button { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } extension Button: PressModifier { @@ -153,4 +162,13 @@ extension LinkButton: ButtonModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> LinkButton { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> LinkButton { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index 3a5210fb..f9e04328 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -139,6 +139,15 @@ extension TextField: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> TextField { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> TextField { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays a editable and expandable form control. @@ -206,6 +215,15 @@ extension TextEditor: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> TextEditor { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> TextEditor { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays a form control @@ -255,6 +273,15 @@ extension CheckField: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> CheckField { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> CheckField { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays @@ -304,6 +331,15 @@ extension RadioSelect: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> RadioSelect { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> RadioSelect { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays @@ -357,6 +393,15 @@ extension SelectField: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> SelectField { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> SelectField { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays @@ -412,6 +457,15 @@ extension SecureField: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> SecureField { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> SecureField { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays @@ -503,6 +557,15 @@ extension DatePicker: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> DatePicker { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> DatePicker { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays @@ -558,6 +621,15 @@ extension SearchField: InputModifier { public func backgroundColor(_ color: Tokens.BackgroundColor) -> SearchField { return self.mutate(backgroundcolor: color.rawValue) } + + public func disabled(_ condition: Bool) -> SearchField { + + if condition { + return self.mutate(state: Tokens.ViewState.disabled.rawValue) + } + + return self + } } /// A component that displays the progress of a task. diff --git a/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift b/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift index f3c79641..f35a690c 100644 --- a/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift @@ -36,6 +36,9 @@ public protocol ButtonModifier { /// /// - Returns: A component func backgroundColor(_ color: Tokens.BackgroundColor) -> Self + + /// Sets the state of the view. + func disabled(_ condition: Bool) -> Self } extension ButtonModifier where Self: Modifiable { @@ -55,4 +58,8 @@ extension ButtonModifier where Self: Modifiable { internal func mutate(backgroundcolor class: String) -> Self { return self.mutate(class: `class`) } + + internal func mutate(state class: String) -> Self { + return self.mutate(class: `class`) + } } diff --git a/Sources/HTMLKitComponents/Modifiers/InputModifier.swift b/Sources/HTMLKitComponents/Modifiers/InputModifier.swift index 427b01ce..6ba48336 100644 --- a/Sources/HTMLKitComponents/Modifiers/InputModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/InputModifier.swift @@ -20,6 +20,9 @@ public protocol InputModifier { /// /// - Returns: A component func backgroundColor(_ color: Tokens.BackgroundColor) -> Self + + /// Sets the state of the view. + func disabled(_ condition: Bool) -> Self } extension InputModifier where Self: Modifiable { @@ -31,5 +34,9 @@ extension InputModifier where Self: Modifiable { internal func mutate(backgroundcolor class: String) -> Self { return self.mutate(class: `class`) } + + internal func mutate(state class: String) -> Self { + return self.mutate(class: `class`) + } } diff --git a/Sources/HTMLKitComponents/Resources/css/carousel.css b/Sources/HTMLKitComponents/Resources/css/carousel.css index c0923cdd..9b804249 100644 --- a/Sources/HTMLKitComponents/Resources/css/carousel.css +++ b/Sources/HTMLKitComponents/Resources/css/carousel.css @@ -67,11 +67,6 @@ cursor: pointer; } -.indicator.state\:active { - border-color: var(--primaryColor); - background-color: var(--primaryColor); -} - .indicator:hover { border-color: var(--primaryColor); background-color: var(--primaryColor); diff --git a/Sources/HTMLKitComponents/Resources/css/utils.css b/Sources/HTMLKitComponents/Resources/css/utils.css index 824336e2..bd02d811 100644 --- a/Sources/HTMLKitComponents/Resources/css/utils.css +++ b/Sources/HTMLKitComponents/Resources/css/utils.css @@ -30,3 +30,12 @@ zindex\:5 { position: relative; z-index: 5; } + +.state\:active { + border-color: var(--primaryColor); + background-color: var(--primaryColor); +} + +.state\:disabled { + pointer-events: none; +} diff --git a/Sources/HTMLKitComponents/Tokens.swift b/Sources/HTMLKitComponents/Tokens.swift index 0f4ff674..9a8455fa 100644 --- a/Sources/HTMLKitComponents/Tokens.swift +++ b/Sources/HTMLKitComponents/Tokens.swift @@ -479,4 +479,11 @@ public enum Tokens { case accordion = "style:accordion" case tab = "style:tab" } + + /// A state to the view. + public enum ViewState: String { + + case active = "state:active" + case disabled = "state:disabled" + } } From 884575e7a771e10db43fbc1ce478b5b59cb2364b Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Tue, 14 Feb 2023 20:23:55 +0100 Subject: [PATCH 18/29] Fix the css classes for the position index --- Sources/HTMLKitComponents/Resources/css/utils.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/HTMLKitComponents/Resources/css/utils.css b/Sources/HTMLKitComponents/Resources/css/utils.css index bd02d811..f4aa1f22 100644 --- a/Sources/HTMLKitComponents/Resources/css/utils.css +++ b/Sources/HTMLKitComponents/Resources/css/utils.css @@ -6,27 +6,27 @@ display: block !important; } -zindex\:1 { +.zindex\:1 { position: relative; z-index: 1; } -zindex\:2 { +.zindex\:2 { position: relative; z-index: 2; } -zindex\:3 { +.zindex\:3 { position: relative; z-index: 3; } -zindex\:4 { +.zindex\:4 { position: relative; z-index: 4; } -zindex\:5 { +.zindex\:5 { position: relative; z-index: 5; } From 25d241768154ef6c05ce9664d1d1d34350707815 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 18 Feb 2023 22:53:29 +0100 Subject: [PATCH 19/29] Add a few new symbols --- Sources/HTMLKitComponents/Components/Symbol.swift | 4 +--- .../HTMLKitComponents/Resources/symbols/clock.svg | 3 +++ .../HTMLKitComponents/Resources/symbols/envelope.svg | 3 +++ Sources/HTMLKitComponents/Resources/symbols/file.svg | 3 +++ .../HTMLKitComponents/Resources/symbols/folder.svg | 12 ++---------- .../HTMLKitComponents/Resources/symbols/person.svg | 3 +++ .../HTMLKitComponents/Resources/symbols/photo.svg | 3 +++ Sources/HTMLKitComponents/Resources/symbols/pie.svg | 3 +++ 8 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 Sources/HTMLKitComponents/Resources/symbols/clock.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/envelope.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/file.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/person.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/photo.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/pie.svg diff --git a/Sources/HTMLKitComponents/Components/Symbol.swift b/Sources/HTMLKitComponents/Components/Symbol.swift index 1073c308..70214129 100644 --- a/Sources/HTMLKitComponents/Components/Symbol.swift +++ b/Sources/HTMLKitComponents/Components/Symbol.swift @@ -49,9 +49,7 @@ public struct Symbol: View, Modifiable { Vector { content } - .width(16) - .height(16) - .viewBox("0 0 16 16") + .viewBox("0 0 20 16") .fill("currentColor") .class(classes.joined(separator: " ")) } diff --git a/Sources/HTMLKitComponents/Resources/symbols/clock.svg b/Sources/HTMLKitComponents/Resources/symbols/clock.svg new file mode 100644 index 00000000..76315edc --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/clock.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Sources/HTMLKitComponents/Resources/symbols/envelope.svg b/Sources/HTMLKitComponents/Resources/symbols/envelope.svg new file mode 100644 index 00000000..3d787661 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/envelope.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/file.svg b/Sources/HTMLKitComponents/Resources/symbols/file.svg new file mode 100644 index 00000000..2c69fb28 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/file.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/folder.svg b/Sources/HTMLKitComponents/Resources/symbols/folder.svg index 86e9a90f..2261870c 100644 --- a/Sources/HTMLKitComponents/Resources/symbols/folder.svg +++ b/Sources/HTMLKitComponents/Resources/symbols/folder.svg @@ -1,11 +1,3 @@ - - - - - - - - - - + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/person.svg b/Sources/HTMLKitComponents/Resources/symbols/person.svg new file mode 100644 index 00000000..00d1c42e --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/person.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/photo.svg b/Sources/HTMLKitComponents/Resources/symbols/photo.svg new file mode 100644 index 00000000..f3ed750d --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/photo.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/pie.svg b/Sources/HTMLKitComponents/Resources/symbols/pie.svg new file mode 100644 index 00000000..a4327e41 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/pie.svg @@ -0,0 +1,3 @@ + + + From 154d007fc9d439229da5d9b7e77ace45c3c56a38 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 19 Feb 2023 21:18:28 +0100 Subject: [PATCH 20/29] Add more symbols --- .../Resources/symbols/{pie.svg => chart.pie.svg} | 0 .../HTMLKitComponents/Resources/symbols/folder.svg | 2 +- Sources/HTMLKitComponents/Resources/symbols/house.svg | 3 +++ Sources/HTMLKitComponents/Resources/symbols/lock.svg | 3 +++ .../Resources/symbols/text.aligncenter.svg | 3 +++ .../Resources/symbols/text.alignjustify.svg | 3 +++ .../Resources/symbols/text.alignleft.svg | 3 +++ .../Resources/symbols/text.alignright.svg | 3 +++ Tests/HTMLKitComponentsTests/ComponentTests.swift | 11 ++--------- 9 files changed, 21 insertions(+), 10 deletions(-) rename Sources/HTMLKitComponents/Resources/symbols/{pie.svg => chart.pie.svg} (100%) create mode 100644 Sources/HTMLKitComponents/Resources/symbols/house.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/lock.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/text.aligncenter.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/text.alignjustify.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/text.alignleft.svg create mode 100644 Sources/HTMLKitComponents/Resources/symbols/text.alignright.svg diff --git a/Sources/HTMLKitComponents/Resources/symbols/pie.svg b/Sources/HTMLKitComponents/Resources/symbols/chart.pie.svg similarity index 100% rename from Sources/HTMLKitComponents/Resources/symbols/pie.svg rename to Sources/HTMLKitComponents/Resources/symbols/chart.pie.svg diff --git a/Sources/HTMLKitComponents/Resources/symbols/folder.svg b/Sources/HTMLKitComponents/Resources/symbols/folder.svg index 2261870c..cc7b772c 100644 --- a/Sources/HTMLKitComponents/Resources/symbols/folder.svg +++ b/Sources/HTMLKitComponents/Resources/symbols/folder.svg @@ -1,3 +1,3 @@ - + diff --git a/Sources/HTMLKitComponents/Resources/symbols/house.svg b/Sources/HTMLKitComponents/Resources/symbols/house.svg new file mode 100644 index 00000000..bc16411c --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/house.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/lock.svg b/Sources/HTMLKitComponents/Resources/symbols/lock.svg new file mode 100644 index 00000000..349375e4 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/text.aligncenter.svg b/Sources/HTMLKitComponents/Resources/symbols/text.aligncenter.svg new file mode 100644 index 00000000..8c99778f --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/text.aligncenter.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/text.alignjustify.svg b/Sources/HTMLKitComponents/Resources/symbols/text.alignjustify.svg new file mode 100644 index 00000000..92cbf6a4 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/text.alignjustify.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/text.alignleft.svg b/Sources/HTMLKitComponents/Resources/symbols/text.alignleft.svg new file mode 100644 index 00000000..5f481377 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/text.alignleft.svg @@ -0,0 +1,3 @@ + + + diff --git a/Sources/HTMLKitComponents/Resources/symbols/text.alignright.svg b/Sources/HTMLKitComponents/Resources/symbols/text.alignright.svg new file mode 100644 index 00000000..d5b08859 --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/symbols/text.alignright.svg @@ -0,0 +1,3 @@ + + + diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index 41827e26..860e8a74 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -529,15 +529,8 @@ final class ComponentTests: XCTestCase { XCTAssertEqual(try renderer.render(view: view), """ - \ - \ - \ - \ - \ - \ - \ - \ - \ + \ + \ """ ) From e3c75ceca4a4853c845b27a3e11a8316836f474a Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 19 Feb 2023 22:34:59 +0100 Subject: [PATCH 21/29] Add the possibility to hide views --- .../HTMLKitComponents/Components/Image.swift | 4 ++++ .../HTMLKitComponents/Components/Stack.swift | 14 +++++++++++- .../Modifiers/ViewModifier.swift | 22 ++++++------------- .../HTMLKitComponents/Resources/css/utils.css | 18 +++++++++------ Sources/HTMLKitComponents/Resources/js/all.js | 10 ++++----- Sources/HTMLKitComponents/Tokens.swift | 2 ++ 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Image.swift b/Sources/HTMLKitComponents/Components/Image.swift index 14aa4820..630fd9a8 100644 --- a/Sources/HTMLKitComponents/Components/Image.swift +++ b/Sources/HTMLKitComponents/Components/Image.swift @@ -66,4 +66,8 @@ extension Image: ViewModifier { public func opacity(_ value: Tokens.OpacityValue) -> Image { return self.mutate(opacity: value.rawValue) } + + public func hidden() -> Image { + return self.mutate(state: Tokens.ViewState.hidden.rawValue) + } } diff --git a/Sources/HTMLKitComponents/Components/Stack.swift b/Sources/HTMLKitComponents/Components/Stack.swift index e5c098f2..ce2aa52e 100644 --- a/Sources/HTMLKitComponents/Components/Stack.swift +++ b/Sources/HTMLKitComponents/Components/Stack.swift @@ -77,7 +77,7 @@ extension HStack: HoverModifier { } extension HStack: ViewModifier { - + public func backgroundColor(_ color: Tokens.BackgroundColor) -> HStack { return self.mutate(backgroundcolor: color.rawValue) } @@ -89,6 +89,10 @@ extension HStack: ViewModifier { public func zIndex(_ index: Tokens.PositionIndex) -> HStack { return self.mutate(zindex: index.rawValue) } + + public func hidden() -> HStack { + return self.mutate(state: Tokens.ViewState.hidden.rawValue) + } } /// A component that arranges content vertically. @@ -164,6 +168,10 @@ extension VStack: ViewModifier { public func zIndex(_ index: Tokens.PositionIndex) -> VStack { return self.mutate(zindex: index.rawValue) } + + public func hidden() -> VStack { + return self.mutate(state: Tokens.ViewState.hidden.rawValue) + } } /// A component that overlays content. @@ -239,6 +247,10 @@ extension ZStack: ViewModifier { public func zIndex(_ index: Tokens.PositionIndex) -> ZStack { return self.mutate(zindex: index.rawValue) } + + public func hidden() -> ZStack { + return self.mutate(state: Tokens.ViewState.hidden.rawValue) + } } /// A component that represents a stack column. diff --git a/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift b/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift index 0c3f1896..cc030086 100644 --- a/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift @@ -6,28 +6,16 @@ public protocol ViewModifier { /// Sets the opacity of the view. - /// - /// - Parameters: - /// - value: - /// - /// - Returns: A component func opacity(_ value: Tokens.OpacityValue) -> Self /// Sets the position of the view. - /// - /// - Parameters: - /// - index: - /// - /// - Returns: A component func zIndex(_ index: Tokens.PositionIndex) -> Self /// Sets the background color of the view. - /// - /// - Parameters: - /// - color: - /// - /// - Returns: A component func backgroundColor(_ color: Tokens.BackgroundColor) -> Self + + /// Hides the view + func hidden() -> Self } extension ViewModifier where Self: Modifiable { @@ -43,4 +31,8 @@ extension ViewModifier where Self: Modifiable { internal func mutate(backgroundcolor class: String) -> Self { return self.mutate(class: `class`) } + + internal func mutate(state class: String) -> Self { + return self.mutate(class: `class`) + } } diff --git a/Sources/HTMLKitComponents/Resources/css/utils.css b/Sources/HTMLKitComponents/Resources/css/utils.css index f4aa1f22..5a6efefb 100644 --- a/Sources/HTMLKitComponents/Resources/css/utils.css +++ b/Sources/HTMLKitComponents/Resources/css/utils.css @@ -2,10 +2,6 @@ utils classes */ -.display\:block { - display: block !important; -} - .zindex\:1 { position: relative; z-index: 1; @@ -32,10 +28,18 @@ } .state\:active { - border-color: var(--primaryColor); - background-color: var(--primaryColor); + border-color: var(--primaryColor) !important; + background-color: var(--primaryColor) !important; } .state\:disabled { - pointer-events: none; + pointer-events: none !important; +} + +.state\:hidden { + display: none !important; +} + +.state\:visible { + display: block !important; } diff --git a/Sources/HTMLKitComponents/Resources/js/all.js b/Sources/HTMLKitComponents/Resources/js/all.js index c91dae7f..523ebb62 100644 --- a/Sources/HTMLKitComponents/Resources/js/all.js +++ b/Sources/HTMLKitComponents/Resources/js/all.js @@ -91,21 +91,21 @@ var $ = (function () { */ constructor.prototype.show = function() { - const elements = document.getElementsByClassName("display:block"); + const elements = document.getElementsByClassName("state:visible"); for (let element of elements){ - element.classList.remove("display:block") + element.classList.remove("state:visible") } - this.elems[0].classList.add("display:block") + this.elems[0].classList.add("state:visible") }; /** * This function is for */ constructor.prototype.hide = function() { - - this.elems[0].classList.remove("display:block") + + this.elems[0].classList.add("state:hidden") }; /** diff --git a/Sources/HTMLKitComponents/Tokens.swift b/Sources/HTMLKitComponents/Tokens.swift index 9a8455fa..7ff473be 100644 --- a/Sources/HTMLKitComponents/Tokens.swift +++ b/Sources/HTMLKitComponents/Tokens.swift @@ -485,5 +485,7 @@ public enum Tokens { case active = "state:active" case disabled = "state:disabled" + case hidden = "state:hidden" + case visible = "state:visible" } } From 3d3463512c084a9392cb47dee9ecb803f13257a8 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 20 Feb 2023 20:45:25 +0100 Subject: [PATCH 22/29] Revise the input fields to accept a placeholder value --- .../HTMLKitComponents/Components/Form.swift | 48 +++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index f9e04328..bea10d4e 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -92,6 +92,9 @@ public struct TextField: View, Modifiable { /// The identifier of the field. internal let name: String + /// The placeholder for the field value. + internal let prompt: String? + /// The content of the field. internal let value: String? @@ -102,17 +105,19 @@ public struct TextField: View, Modifiable { internal var events: [String]? /// Creates a text field. - public init(name: String, value: String? = nil) { + public init(name: String, prompt: String? = nil, value: String? = nil) { self.name = name + self.prompt = prompt self.value = value self.classes = ["input", "type:textfield"] } /// Creates a text field. - internal init(name: String, value: String?, classes: [String], events: [String]?) { + internal init(name: String, prompt: String?, value: String?, classes: [String], events: [String]?) { self.name = name + self.prompt = prompt self.value = value self.classes = classes self.events = events @@ -127,6 +132,9 @@ public struct TextField: View, Modifiable { .modify(unwrap: value) { $0.value($1) } + .modify(unwrap: prompt) { + $0.placeholder($1) + } } } @@ -156,6 +164,9 @@ public struct TextEditor: View, Modifiable { /// The identifier of the editor. internal let name: String + /// The placeholder for the field value. + internal let prompt: String? + /// The number of lines. internal var rows: Int = 1 @@ -169,17 +180,19 @@ public struct TextEditor: View, Modifiable { internal var events: [String]? /// Creates a text editor. - public init(name: String, @ContentBuilder content: () -> [String]) { + public init(name: String, prompt: String? = nil, @ContentBuilder content: () -> [String]) { self.name = name + self.prompt = prompt self.content = content() self.classes = ["input", "type:texteditor"] } /// Creates a text editor. - internal init(name: String, rows: Int, content: [String], classes: [String], events: [String]?) { + internal init(name: String, prompt: String?, rows: Int, content: [String], classes: [String], events: [String]?) { self.name = name + self.prompt = prompt self.rows = rows self.content = content self.classes = classes @@ -194,6 +207,9 @@ public struct TextEditor: View, Modifiable { .name(name) .class(classes.joined(separator: " ")) .rows(rows) + .modify(unwrap: prompt) { + $0.placeholder($1) + } } /// Sets the limit of the maximum lines. @@ -410,6 +426,9 @@ public struct SecureField: View, Modifiable { /// The identifier of the field. internal let name: String + /// The placeholder for the field value. + internal let prompt: String? + /// The content of the field. internal let value: String? @@ -420,17 +439,19 @@ public struct SecureField: View, Modifiable { internal var events: [String]? /// Creates a password field. - public init(name: String, value: String? = nil) { + public init(name: String, prompt: String? = nil, value: String? = nil) { self.name = name + self.prompt = prompt self.value = value self.classes = ["input", "type:securefield"] } /// Creates a password field. - internal init(name: String, value: String?, classes: [String], events: [String]?) { + internal init(name: String, prompt: String?, value: String?, classes: [String], events: [String]?) { self.name = name + self.prompt = prompt self.value = value self.classes = classes self.events = events @@ -445,6 +466,9 @@ public struct SecureField: View, Modifiable { .modify(unwrap: value) { $0.value($1) } + .modify(unwrap: prompt) { + $0.placeholder($1) + } } } @@ -574,6 +598,9 @@ public struct SearchField: View, Modifiable { /// The identifier of the search field. internal let name: String + /// The placeholder for the field value. + internal let prompt: String? + /// The content of the field. internal let value: String? @@ -584,17 +611,19 @@ public struct SearchField: View, Modifiable { internal var events: [String]? /// Creates a search field. - public init(name: String, value: String? = nil) { + public init(name: String, prompt: String? = nil, value: String? = nil) { self.name = name + self.prompt = prompt self.value = value self.classes = ["input", "type:searchfield"] } /// Creates a search field. - internal init(name: String, value: String?, classes: [String], events: [String]?) { + internal init(name: String, prompt: String?, value: String?, classes: [String], events: [String]?) { self.name = name + self.prompt = prompt self.value = value self.classes = classes self.events = events @@ -609,6 +638,9 @@ public struct SearchField: View, Modifiable { .modify(unwrap: value) { $0.value($1) } + .modify(unwrap: prompt) { + $0.placeholder($1) + } } } From 81a0b8d27afb84d4a2e5d1f07607b944b68a2e41 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Thu, 23 Feb 2023 16:42:51 +0100 Subject: [PATCH 23/29] Add the submit event to the form component --- .../HTMLKitComponents/Components/Form.swift | 27 +++++++++++++++++-- .../Modifiers/FormModifier.swift | 17 ++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 Sources/HTMLKitComponents/Modifiers/FormModifier.swift diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index bea10d4e..074e7613 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -6,7 +6,10 @@ import HTMLKit /// A component that collects form controls. -public struct Form: View { +public struct Form: View, Actionable { + + /// The identifier of the form. + internal var id: String? internal var method: HTMLKit.Values.Method @@ -28,12 +31,13 @@ public struct Form: View { } /// Creates a form container. - internal init(method: Values.Method, content: [FormElement], classes: [String], events: [String]?) { + internal init(method: Values.Method, content: [FormElement], classes: [String], events: [String]?, id: String?) { self.method = method self.content = content self.classes = classes self.events = events + self.id = id } public var body: Content { @@ -42,6 +46,25 @@ public struct Form: View { } .method(method) .class(classes.joined(separator: " ")) + .modify(unwrap: id) { + $0.id($1) + } + if let events = self.events { + Script { + events + } + } + } + + public func id(_ value: String) -> Form { + return self.mutate(id: value) + } +} + +extension Form: FormModifier { + + public func onSubmit(perfom action: Actions) -> Form { + return self.mutate(submitevent: action.script) } } diff --git a/Sources/HTMLKitComponents/Modifiers/FormModifier.swift b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift new file mode 100644 index 00000000..6f038708 --- /dev/null +++ b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift @@ -0,0 +1,17 @@ +public protocol FormModifier { + + /// Acts on a submit event. + func onSubmit(perfom action: Actions) -> Self +} + +extension FormModifier where Self: Actionable { + + internal func mutate(submitevent script: String) -> Self { + + guard let identifier = self.id else { + fatalError("Initiative identifier unkown.") + } + + return self.mutate(event: Events.submit(selector: identifier, script: script)) + } +} From 4c33834e0b1dd92b55655266df898c1eeed24d05 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 25 Feb 2023 14:06:24 +0100 Subject: [PATCH 24/29] Add comments --- Sources/HTMLKitComponents/Actions.swift | 18 ++++++++- .../HTMLKitComponents/Components/Card.swift | 12 ++++++ .../Components/Carousel.swift | 8 +++- .../Components/Dropdown.swift | 5 +++ .../HTMLKitComponents/Components/Form.swift | 6 +-- .../HTMLKitComponents/Components/Grid.swift | 2 +- .../HTMLKitComponents/Components/Group.swift | 1 + .../HTMLKitComponents/Components/Image.swift | 2 +- .../HTMLKitComponents/Components/Modal.swift | 10 +++++ .../Components/ScrollView.swift | 4 ++ .../HTMLKitComponents/Components/Symbol.swift | 1 + .../HTMLKitComponents/Components/Toggle.swift | 2 +- Sources/HTMLKitComponents/Events.swift | 13 ++++++- .../Modifiers/ButtonModifier.swift | 21 +---------- .../Modifiers/DragModifier.swift | 9 +++++ .../Modifiers/FormModifier.swift | 6 +++ .../Modifiers/HoverModifier.swift | 9 +++++ .../Modifiers/ImageModifier.swift | 16 +------- .../Modifiers/InputModifier.swift | 11 +----- .../Modifiers/PressModifier.swift | 10 +++++ .../Modifiers/TextModifier.swift | 37 +------------------ .../Modifiers/ViewModifier.swift | 1 + .../Properties/Actionable.swift | 7 ++++ .../Properties/Identifiable.swift | 7 +--- .../Properties/Modifiable.swift | 3 ++ Sources/HTMLKitComponents/Resources/js/all.js | 30 +++++++-------- Sources/HTMLKitComponents/Tokens.swift | 29 ++++++++++++--- 27 files changed, 164 insertions(+), 116 deletions(-) diff --git a/Sources/HTMLKitComponents/Actions.swift b/Sources/HTMLKitComponents/Actions.swift index aed9d6b2..5a7b6d48 100644 --- a/Sources/HTMLKitComponents/Actions.swift +++ b/Sources/HTMLKitComponents/Actions.swift @@ -1,16 +1,27 @@ /* Abstract: - The file contains the actions for the components. + The file contains the action stencils for the components. */ +/// A collection of actions, that can be triggered by events. public enum Actions { + /// Shows the target. case show(_ target: String) + + /// Hides the target. case hide(_ target: String) + + /// Animates the target. case animate(_ target: String) + + /// Opens the target. case open(_ target: String) + + /// Closes the target. case close(_ target: String) + /// The script for the action. public var script: String { switch self { @@ -31,22 +42,27 @@ public enum Actions { } } + /// Returns a show action stencil. private func show(_ target: String) -> String { return "$('#\(target)').show();" } + /// Returns a hide action stencil. private func hide(_ target: String) -> String { return "$('#\(target)').hide();" } + /// Returns a animate action stencil. private func animate(_ target: String) -> String { return "$('#\(target)').animate();" } + /// Returns a open action stencil. private func open(_ target: String) -> String { return "$('#\(target)').open();" } + /// Returns a close action stencil. private func close(_ target: String) -> String { return "$('#\(target)').close();" } diff --git a/Sources/HTMLKitComponents/Components/Card.swift b/Sources/HTMLKitComponents/Components/Card.swift index 62a3ec4d..48599fad 100644 --- a/Sources/HTMLKitComponents/Components/Card.swift +++ b/Sources/HTMLKitComponents/Components/Card.swift @@ -1,18 +1,30 @@ +/* + Abstract: + The file contains a card component. + */ + import HTMLKit +/// A component that distinguish content. public class Card: View { + /// The header of the card. public var header: [Content]? + + /// The content of the card. public var content: [Content] + /// The classes of the content. internal var classes: [String] + /// Creates a card. public init(@ContentBuilder content: () -> [Content]) { self.content = content() self.classes = ["card"] } + /// Creates a card. public init(@ContentBuilder content: () -> [Content], @ContentBuilder header: () -> [Content]) { diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift index a22225ad..5e591017 100644 --- a/Sources/HTMLKitComponents/Components/Carousel.swift +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -1,18 +1,23 @@ /* Abstract: - The file contains everything related to the carousel component. + The file contains a carousel component. */ import HTMLKit +/// A compnonent that cycles through an amount of views. public struct Carousel: View { + /// The indication for the carousel. internal var indication: [Content] + /// The content of the carousel. internal var content: [Content] + /// The classes of the carousel. internal var classes: [String] + /// Creates a carousel. public init(@ContentBuilder content: () -> [Content], @ContentBuilder indication: () -> [Content]) { @@ -21,6 +26,7 @@ public struct Carousel: View { self.classes = ["carousel"] } + /// Creates a carousel. internal init(indication: [Content], content: [Content], classes: [String]) { self.indication = indication diff --git a/Sources/HTMLKitComponents/Components/Dropdown.swift b/Sources/HTMLKitComponents/Components/Dropdown.swift index 5c3dbd37..f2e30457 100644 --- a/Sources/HTMLKitComponents/Components/Dropdown.swift +++ b/Sources/HTMLKitComponents/Components/Dropdown.swift @@ -5,14 +5,19 @@ import HTMLKit +/// A component that displays a list of actions. public struct Dropdown: View { + /// The label for the dropdown. internal var label: [Content] + /// The content of the dropdown. internal var content: [Content] + /// The classes of the dropdown. internal var classes: [String] + /// Creates a dropdown. public init(@ContentBuilder content: () -> [Content], @ContentBuilder label: () -> [Content]) { self.label = label() diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index 074e7613..a49b09ab 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -1,6 +1,6 @@ /* Abstract: - The file contains everything related to form. + The file contains everything related to form component. */ import HTMLKit @@ -22,7 +22,7 @@ public struct Form: View, Actionable { /// The events of the container. internal var events: [String]? - /// Creates a form container. + /// Creates a form. public init(method: Values.Method, @ContentBuilder content: () -> [FormElement]) { self.method = method @@ -30,7 +30,7 @@ public struct Form: View, Actionable { self.classes = ["form"] } - /// Creates a form container. + /// Creates a form. internal init(method: Values.Method, content: [FormElement], classes: [String], events: [String]?, id: String?) { self.method = method diff --git a/Sources/HTMLKitComponents/Components/Grid.swift b/Sources/HTMLKitComponents/Components/Grid.swift index 7d84f0d5..7bc9fd6c 100644 --- a/Sources/HTMLKitComponents/Components/Grid.swift +++ b/Sources/HTMLKitComponents/Components/Grid.swift @@ -1,6 +1,6 @@ /* Abstract: - The file contains everything related to the collection. + The file contains everything related to the grid component. */ import HTMLKit diff --git a/Sources/HTMLKitComponents/Components/Group.swift b/Sources/HTMLKitComponents/Components/Group.swift index 46e2c03c..4355f81d 100644 --- a/Sources/HTMLKitComponents/Components/Group.swift +++ b/Sources/HTMLKitComponents/Components/Group.swift @@ -1,5 +1,6 @@ /* Abstract: + The file contains everything related to the group component. */ import HTMLKit diff --git a/Sources/HTMLKitComponents/Components/Image.swift b/Sources/HTMLKitComponents/Components/Image.swift index 630fd9a8..418cdd09 100644 --- a/Sources/HTMLKitComponents/Components/Image.swift +++ b/Sources/HTMLKitComponents/Components/Image.swift @@ -1,6 +1,6 @@ /* Abstract: - The file contains everything related to images. + The file contains everything related to image component. */ import HTMLKit diff --git a/Sources/HTMLKitComponents/Components/Modal.swift b/Sources/HTMLKitComponents/Components/Modal.swift index 0a415e45..d248ba13 100644 --- a/Sources/HTMLKitComponents/Components/Modal.swift +++ b/Sources/HTMLKitComponents/Components/Modal.swift @@ -1,15 +1,25 @@ +/* + Abstract: + The file contains a modal component. + */ + import HTMLKit +/// A component that presents a dialog on top of other views. public struct Modal: View, Modifiable, Actionable { internal var id: String? + /// The content of the modal. internal var content: [Content] + /// The classes of the modal. internal var classes: [String] + /// The events of the modal. internal var events: [String]? + /// Creates a modal. public init(@ContentBuilder content: () -> [Content]) { self.content = content() diff --git a/Sources/HTMLKitComponents/Components/ScrollView.swift b/Sources/HTMLKitComponents/Components/ScrollView.swift index 5198405f..a1dfc723 100644 --- a/Sources/HTMLKitComponents/Components/ScrollView.swift +++ b/Sources/HTMLKitComponents/Components/ScrollView.swift @@ -5,12 +5,16 @@ import HTMLKit +/// A component that displays content in its scrollable area. public struct ScrollView: View { + /// The content of the scrollview. internal var content: [Content] + /// The classes of the scrollview. internal var classes: [String] + /// Creates a scrollview. public init(direction: Tokens.FlowDirection, @ContentBuilder content: () -> [Content]) { self.content = content() diff --git a/Sources/HTMLKitComponents/Components/Symbol.swift b/Sources/HTMLKitComponents/Components/Symbol.swift index 70214129..b5895d71 100644 --- a/Sources/HTMLKitComponents/Components/Symbol.swift +++ b/Sources/HTMLKitComponents/Components/Symbol.swift @@ -11,6 +11,7 @@ import OrderedCollections import FoundationXML #endif +/// A component that displays symbols. public struct Symbol: View, Modifiable { /// The content of the symbol. diff --git a/Sources/HTMLKitComponents/Components/Toggle.swift b/Sources/HTMLKitComponents/Components/Toggle.swift index fa2c3e9d..b2ae8176 100644 --- a/Sources/HTMLKitComponents/Components/Toggle.swift +++ b/Sources/HTMLKitComponents/Components/Toggle.swift @@ -1,6 +1,6 @@ /* Abstract: - The file contains everything related to the text component. + The file contains everything related to the toggle component. */ import HTMLKit diff --git a/Sources/HTMLKitComponents/Events.swift b/Sources/HTMLKitComponents/Events.swift index 54e8fb2a..06c48f15 100644 --- a/Sources/HTMLKitComponents/Events.swift +++ b/Sources/HTMLKitComponents/Events.swift @@ -1,10 +1,12 @@ /* Abstract: - The file contains the script stencils for the js. + The file contains the event stencils for the components. */ +/// A collection of events, that can occur on components. public enum Events { + /// Returns a hover event stencil. static func hover(selector: String, script: String) -> String { return """ @@ -14,6 +16,7 @@ public enum Events { """ } + /// Returns a leave event stencil. static func leave(selector: String, script: String) -> String { return """ @@ -23,6 +26,7 @@ public enum Events { """ } + /// Returns a change event stencil. static func change(selector: String, script: String) -> String { return """ @@ -32,6 +36,7 @@ public enum Events { """ } + /// Returns a click event stencil. static func click(selector: String, script: String) -> String { return """ @@ -41,6 +46,7 @@ public enum Events { """ } + /// Returns a tap gesture stencil. static func tap(selector: String, script: String) -> String { return """ @@ -50,6 +56,7 @@ public enum Events { """ } + /// Returns a long press gesture stencil. static func press(selector: String, script: String) -> String { return """ @@ -59,6 +66,7 @@ public enum Events { """ } + /// Returns a drag event stencil. static func drag(selector: String, script: String) -> String { return """ @@ -68,6 +76,7 @@ public enum Events { """ } + /// Returns a drop event stencil. static func drop(selector: String, script: String) -> String { return """ @@ -77,6 +86,7 @@ public enum Events { """ } + /// Returns a focus event stencil. static func focus(selector: String, script: String) -> String { return """ @@ -86,6 +96,7 @@ public enum Events { """ } + /// Returns a submit event stencil. static func submit(selector: String, script: String) -> String { return """ diff --git a/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift b/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift index f35a690c..b097d921 100644 --- a/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/ButtonModifier.swift @@ -3,38 +3,19 @@ The file contains the modifiers for button components. */ +/// A type that describes the modifier of a button component. public protocol ButtonModifier { /// Sets the size of the button. - /// - /// - Parameters: - /// - size: - /// - /// - Returns: A component func buttonSize(_ size: Tokens.ButtonSize) -> Self /// Sets the style of the button. - /// - /// - Parameters: - /// - style: - /// - /// - Returns: A component func buttonStyle(_ style: Tokens.ButtonStyle) -> Self /// Sets the shape of the button. - /// - /// - Parameters: - /// - shape: - /// - /// - Returns: A component func borderShape(_ shape: Tokens.BorderShape) -> Self /// Sets the background color. - /// - /// - Parameters: - /// - color: - /// - /// - Returns: A component func backgroundColor(_ color: Tokens.BackgroundColor) -> Self /// Sets the state of the view. diff --git a/Sources/HTMLKitComponents/Modifiers/DragModifier.swift b/Sources/HTMLKitComponents/Modifiers/DragModifier.swift index 1d96e790..21da6a24 100644 --- a/Sources/HTMLKitComponents/Modifiers/DragModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/DragModifier.swift @@ -1,9 +1,18 @@ +/* + Abstract: + The file contains the modifiers for components with drag interaction. + */ + +/// A type that describes the modifier of a draggable component. public protocol DragModifier { + /// The identifier of the component. func id(_ value: String) -> Self + /// Acts on a drag event. func onDrag(perfom action: Actions) -> Self + /// Acts on a drop event func onDrop(perfom action: Actions) -> Self } diff --git a/Sources/HTMLKitComponents/Modifiers/FormModifier.swift b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift index 6f038708..5733c7b6 100644 --- a/Sources/HTMLKitComponents/Modifiers/FormModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift @@ -1,3 +1,9 @@ +/* + Abstract: + The file contains the modifiers for form component. + */ + +/// A type that describes the modifier of a form component. public protocol FormModifier { /// Acts on a submit event. diff --git a/Sources/HTMLKitComponents/Modifiers/HoverModifier.swift b/Sources/HTMLKitComponents/Modifiers/HoverModifier.swift index 502dff10..20f62137 100644 --- a/Sources/HTMLKitComponents/Modifiers/HoverModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/HoverModifier.swift @@ -1,9 +1,18 @@ +/* + Abstract: + The file contains the modifiers for components with hover interaction. + */ + +/// A type that describes the modifier of a hoverable component. public protocol HoverModifier { + /// The identifier of the component. func id(_ value: String) -> Self + /// Acts on a hover event. func onHover(perfom action: Actions) -> Self + /// Acts on a leave event. func onLeave(perfom action: Actions) -> Self } diff --git a/Sources/HTMLKitComponents/Modifiers/ImageModifier.swift b/Sources/HTMLKitComponents/Modifiers/ImageModifier.swift index c6033160..7e529eef 100644 --- a/Sources/HTMLKitComponents/Modifiers/ImageModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/ImageModifier.swift @@ -3,30 +3,16 @@ The file contains the modifiers for image components. */ +/// A type that describes the modifier of a image component. public protocol ImageModifier { /// Sets how the content should be resized to fit its parent. - /// - /// - Parameters: - /// - fit: The fit - /// - /// - Returns: A component func objectFit(_ fit: Tokens.ObjectFit) -> Self /// Sets the scale of the image. - /// - /// - Parameters: - /// - scale: The scale - /// - /// - Returns: A component func imageScale(_ scale: Tokens.ImageScale) -> Self /// Sets the fill style to use. - /// - /// - Parameters: - /// - shape: The fill style to use. - /// - /// - Returns: A component func clipShape(_ shape: Tokens.ClipShape) -> Self } diff --git a/Sources/HTMLKitComponents/Modifiers/InputModifier.swift b/Sources/HTMLKitComponents/Modifiers/InputModifier.swift index 6ba48336..07e10a83 100644 --- a/Sources/HTMLKitComponents/Modifiers/InputModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/InputModifier.swift @@ -3,22 +3,13 @@ The file contains the modifiers for input components. */ +/// A type that describes the modifier of a input component. public protocol InputModifier { /// Sets the border shape of the input. - /// - /// - Parameters: - /// - shape: - /// - /// - Returns: A component func borderShape(_ shape: Tokens.BorderShape) -> Self /// Sets the background color of the input. - /// - /// - Parameters: - /// - color: - /// - /// - Returns: A component func backgroundColor(_ color: Tokens.BackgroundColor) -> Self /// Sets the state of the view. diff --git a/Sources/HTMLKitComponents/Modifiers/PressModifier.swift b/Sources/HTMLKitComponents/Modifiers/PressModifier.swift index ab44e46e..4e27cd7d 100644 --- a/Sources/HTMLKitComponents/Modifiers/PressModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/PressModifier.swift @@ -1,11 +1,21 @@ +/* + Abstract: + The file contains the modifiers for components with press interaction. + */ + +/// A type thats describes the modifier of a pressable component. public protocol PressModifier { + /// The identifier of the component. func id(_ value: String) -> Self + /// Acts on a click event. func onClick(perfom action: Actions) -> Self + /// Acts on a tap event. func onTap(perfom action: Actions) -> Self + /// Acts on a press event. func onPress(perfom action: Actions) -> Self } diff --git a/Sources/HTMLKitComponents/Modifiers/TextModifier.swift b/Sources/HTMLKitComponents/Modifiers/TextModifier.swift index 2f65e87d..33a69a94 100644 --- a/Sources/HTMLKitComponents/Modifiers/TextModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/TextModifier.swift @@ -3,69 +3,34 @@ The file contains the modifiers for text components. */ +/// A type that describes the modifier of a text component. public protocol TextModifier { /// Sets the style of the text. - /// - /// - Parameters: - /// - style: - /// - /// - Returns: A component func font(_ style: Tokens.TextStyle) -> Self /// Sets the foreground color of the text. - /// - /// - Parameters: - /// - color: - /// - /// - Returns: A component func foregroundColor(_ color: Tokens.ForegroundColor) -> Self /// Sets the size of the text. - /// - /// - Parameters: - /// - size: - /// - /// - Returns: A component func fontSize(_ size: Tokens.FontSize) -> Self /// Sets the weight of the text. - /// - /// - Parameters: - /// - weight: - /// - /// - Returns: func fontWeight(_ weight: Tokens.FontWeight) -> Self /// Sets the transformation for the text. - /// - /// - Parameters: - /// - transformation: - /// - /// - Returns: A component func fontTransformation(_ transformation: Tokens.TextTransformation) -> Self /// Sets the style of the font. - /// - /// - Parameters: - /// - style: - /// - /// - Returns: A component func fontStyle(_ style: Tokens.FontStyle) -> Self /// Applies a bold font weight to the text. - /// - /// - Returns: A component func bold() -> Self /// Applies italics to the text. - /// - /// - Returns: A component func italic() -> Self /// Applies an underline to the text. - /// - /// - Returns: A component func underline() -> Self } diff --git a/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift b/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift index cc030086..a3be0178 100644 --- a/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/ViewModifier.swift @@ -3,6 +3,7 @@ The file contains the modifiers for view components. */ +/// A type that describes the modifier of a view. public protocol ViewModifier { /// Sets the opacity of the view. diff --git a/Sources/HTMLKitComponents/Properties/Actionable.swift b/Sources/HTMLKitComponents/Properties/Actionable.swift index fcc4efd5..7b650b53 100644 --- a/Sources/HTMLKitComponents/Properties/Actionable.swift +++ b/Sources/HTMLKitComponents/Properties/Actionable.swift @@ -1,5 +1,12 @@ +/* + Abstract: + The file contains + */ + +/// A type that describes a component with events. internal protocol Actionable: Identifiable { + /// The events of the component. var events: [String]? { get set } } diff --git a/Sources/HTMLKitComponents/Properties/Identifiable.swift b/Sources/HTMLKitComponents/Properties/Identifiable.swift index 27f508d1..955ee72d 100644 --- a/Sources/HTMLKitComponents/Properties/Identifiable.swift +++ b/Sources/HTMLKitComponents/Properties/Identifiable.swift @@ -1,10 +1,5 @@ -// -// File.swift -// -// -// Created by Mattes Mohr on 25.12.22. -// +/// A type that describes a component with an identifier. internal protocol Identifiable { /// The identifier of the component. diff --git a/Sources/HTMLKitComponents/Properties/Modifiable.swift b/Sources/HTMLKitComponents/Properties/Modifiable.swift index b47c9d8e..5e60e812 100644 --- a/Sources/HTMLKitComponents/Properties/Modifiable.swift +++ b/Sources/HTMLKitComponents/Properties/Modifiable.swift @@ -1,5 +1,8 @@ + +/// A type that describes a component with classes. internal protocol Modifiable { + /// The classes of the component. var classes: [String] { get set } } diff --git a/Sources/HTMLKitComponents/Resources/js/all.js b/Sources/HTMLKitComponents/Resources/js/all.js index 523ebb62..39e80823 100644 --- a/Sources/HTMLKitComponents/Resources/js/all.js +++ b/Sources/HTMLKitComponents/Resources/js/all.js @@ -7,7 +7,7 @@ var $ = (function () { }; /** - * This function is for + * Peforms when the pointer enters the target area. */ constructor.prototype.onHover = function (callback) { @@ -15,7 +15,7 @@ var $ = (function () { }; /** - * This function is for + * Peforms when the pointer leaves the target area. */ constructor.prototype.onLeave = function (callback) { @@ -23,7 +23,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target value changes. */ constructor.prototype.onChange = function (callback) { @@ -31,7 +31,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is clicked. */ constructor.prototype.onClick = function (callback) { @@ -39,7 +39,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is touched. */ constructor.prototype.onTapGesture = function (callback) { @@ -47,7 +47,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is touched. */ constructor.prototype.onLongPressGesture = function (callback) { @@ -55,7 +55,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is dragged. */ constructor.prototype.onDrag = function (callback) { @@ -63,7 +63,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is dropped. */ constructor.prototype.onDrop = function (callback) { @@ -71,7 +71,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is focused. */ constructor.prototype.onFocus = function (callback) { @@ -79,7 +79,7 @@ var $ = (function () { }; /** - * This function is for + * Performs when the target is submitted. */ constructor.prototype.onSubmit = function (callback) { @@ -87,7 +87,7 @@ var $ = (function () { }; /** - * This function is for + * Shows the target. */ constructor.prototype.show = function() { @@ -101,7 +101,7 @@ var $ = (function () { }; /** - * This function is for + * Hides the target. */ constructor.prototype.hide = function() { @@ -109,7 +109,7 @@ var $ = (function () { }; /** - * This function is for + * Animates the target. */ constructor.prototype.animate = function({params}, speed) { @@ -117,7 +117,7 @@ var $ = (function () { }; /** - * This function is for + * Opens the dialog. */ constructor.prototype.open = function() { @@ -125,7 +125,7 @@ var $ = (function () { }; /** - * This function is for + * Closes the dialog. */ constructor.prototype.close = function() { diff --git a/Sources/HTMLKitComponents/Tokens.swift b/Sources/HTMLKitComponents/Tokens.swift index 7ff473be..664a7dcf 100644 --- a/Sources/HTMLKitComponents/Tokens.swift +++ b/Sources/HTMLKitComponents/Tokens.swift @@ -1,8 +1,9 @@ /* Abstract: - The file contains the class tokens for the css. + The file contains the class tokens for the components. */ +/// A collection of class tokens for the components. public enum Tokens { /// A direction for elements. @@ -439,6 +440,7 @@ public enum Tokens { case outline = "style:outline" } + /// A shape of the button. public enum BorderShape: String { case smallrounded = "shape:smallrounded" @@ -456,20 +458,30 @@ public enum Tokens { /// Sets the size to 75 %. case large = "size:large" - /// Sets the size to 50%. + /// Sets the size to 50 %. case medium = "size:medium" /// Sets the size to 25 %. case small = "size:small" } + /// A ratio for the grid. public enum ItemRatio: String { + /// Sets the ratio to 15%. + case sixth = "ratio:15" + + /// Sets the ratio to 20 %. + case fifth = "ratio:20" + + /// Sets the ratio to 25 %. case quarter = "ratio:25" + + /// Sets the ratio to 33 %. case third = "ratio:33" + + /// Sets the ratio to 50 %. case half = "ratio:50" - case fifth = "ratio:20" - case sixth = "ratio:15" } /// A style for a list. @@ -480,12 +492,19 @@ public enum Tokens { case tab = "style:tab" } - /// A state to the view. + /// A state for the view. public enum ViewState: String { + /// Sets the state to active. case active = "state:active" + + /// Sets the state to disabled. case disabled = "state:disabled" + + /// Sets the state to hidden. case hidden = "state:hidden" + + /// Sets the state to visible. case visible = "state:visible" } } From 4fef16aa183d66bbf375f978904214d45c91d5d8 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sat, 25 Feb 2023 15:48:50 +0100 Subject: [PATCH 25/29] Refactor code and rearrange files --- Sources/HTMLKit/Abstraction/README.md | 10 ++++++++++ .../{Core => }/Builders/ContentBuilder.swift | 0 .../Environment/{Storage => }/Environment.swift | 0 .../{Storage => }/EnvironmentKeys.swift | 0 .../{Storage => }/EnvironmentModifier.swift | 0 .../{Storage => }/EnvironmentObject.swift | 0 .../{Storage => }/EnvironmentValue.swift | 0 .../Environment/{Storage => }/Manager.swift | 0 .../Extensions/Datatypes+Content.swift | 0 .../{Core => }/Helpers/Geometrics.swift | 0 .../Localization/Localizable.swift | 0 .../Localization/LocalizedStringKey.swift | 0 .../Primitives/Attributes/Attribute.swift | 0 .../Primitives/Elements/Element.swift | 0 .../Primitives/Elements/Elements.swift | 0 .../{Core => }/Primitives/Layouts/Layouts.swift | 0 .../{Core => }/Primitives/Nodes/Node.swift | 0 .../{Core => }/Primitives/Nodes/Nodes.swift | 0 .../{Core => }/Primitives/Shared/Content.swift | 0 Sources/HTMLKit/Framework/README.md | 17 +++++++++++++++++ Sources/HTMLKitComponents/Components/Card.swift | 8 ++++++++ .../HTMLKitComponents/Components/Dropdown.swift | 8 ++++++++ .../HTMLKitComponents/Components/Modal.swift | 9 +++++++++ .../Components/ScrollView.swift | 7 +++++++ Sources/HTMLKitComponents/Events.swift | 2 +- 25 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 Sources/HTMLKit/Abstraction/README.md rename Sources/HTMLKit/Framework/{Core => }/Builders/ContentBuilder.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/Environment.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/EnvironmentKeys.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/EnvironmentModifier.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/EnvironmentObject.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/EnvironmentValue.swift (100%) rename Sources/HTMLKit/Framework/Environment/{Storage => }/Manager.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Extensions/Datatypes+Content.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Helpers/Geometrics.swift (100%) rename Sources/HTMLKit/Framework/{Environment => }/Localization/Localizable.swift (100%) rename Sources/HTMLKit/Framework/{Environment => }/Localization/LocalizedStringKey.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Attributes/Attribute.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Elements/Element.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Elements/Elements.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Layouts/Layouts.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Nodes/Node.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Nodes/Nodes.swift (100%) rename Sources/HTMLKit/Framework/{Core => }/Primitives/Shared/Content.swift (100%) create mode 100644 Sources/HTMLKit/Framework/README.md diff --git a/Sources/HTMLKit/Abstraction/README.md b/Sources/HTMLKit/Abstraction/README.md new file mode 100644 index 00000000..388e4a3b --- /dev/null +++ b/Sources/HTMLKit/Abstraction/README.md @@ -0,0 +1,10 @@ +# Abstraction + +This directory contains the HTML abstraction. + +### Attributes + +### Elements + +### Tokens + diff --git a/Sources/HTMLKit/Framework/Core/Builders/ContentBuilder.swift b/Sources/HTMLKit/Framework/Builders/ContentBuilder.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Builders/ContentBuilder.swift rename to Sources/HTMLKit/Framework/Builders/ContentBuilder.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/Environment.swift b/Sources/HTMLKit/Framework/Environment/Environment.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/Environment.swift rename to Sources/HTMLKit/Framework/Environment/Environment.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/EnvironmentKeys.swift b/Sources/HTMLKit/Framework/Environment/EnvironmentKeys.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/EnvironmentKeys.swift rename to Sources/HTMLKit/Framework/Environment/EnvironmentKeys.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/EnvironmentModifier.swift b/Sources/HTMLKit/Framework/Environment/EnvironmentModifier.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/EnvironmentModifier.swift rename to Sources/HTMLKit/Framework/Environment/EnvironmentModifier.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/EnvironmentObject.swift b/Sources/HTMLKit/Framework/Environment/EnvironmentObject.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/EnvironmentObject.swift rename to Sources/HTMLKit/Framework/Environment/EnvironmentObject.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/EnvironmentValue.swift b/Sources/HTMLKit/Framework/Environment/EnvironmentValue.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/EnvironmentValue.swift rename to Sources/HTMLKit/Framework/Environment/EnvironmentValue.swift diff --git a/Sources/HTMLKit/Framework/Environment/Storage/Manager.swift b/Sources/HTMLKit/Framework/Environment/Manager.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Storage/Manager.swift rename to Sources/HTMLKit/Framework/Environment/Manager.swift diff --git a/Sources/HTMLKit/Framework/Core/Extensions/Datatypes+Content.swift b/Sources/HTMLKit/Framework/Extensions/Datatypes+Content.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Extensions/Datatypes+Content.swift rename to Sources/HTMLKit/Framework/Extensions/Datatypes+Content.swift diff --git a/Sources/HTMLKit/Framework/Core/Helpers/Geometrics.swift b/Sources/HTMLKit/Framework/Helpers/Geometrics.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Helpers/Geometrics.swift rename to Sources/HTMLKit/Framework/Helpers/Geometrics.swift diff --git a/Sources/HTMLKit/Framework/Environment/Localization/Localizable.swift b/Sources/HTMLKit/Framework/Localization/Localizable.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Localization/Localizable.swift rename to Sources/HTMLKit/Framework/Localization/Localizable.swift diff --git a/Sources/HTMLKit/Framework/Environment/Localization/LocalizedStringKey.swift b/Sources/HTMLKit/Framework/Localization/LocalizedStringKey.swift similarity index 100% rename from Sources/HTMLKit/Framework/Environment/Localization/LocalizedStringKey.swift rename to Sources/HTMLKit/Framework/Localization/LocalizedStringKey.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Attributes/Attribute.swift b/Sources/HTMLKit/Framework/Primitives/Attributes/Attribute.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Attributes/Attribute.swift rename to Sources/HTMLKit/Framework/Primitives/Attributes/Attribute.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Elements/Element.swift b/Sources/HTMLKit/Framework/Primitives/Elements/Element.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Elements/Element.swift rename to Sources/HTMLKit/Framework/Primitives/Elements/Element.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Elements/Elements.swift b/Sources/HTMLKit/Framework/Primitives/Elements/Elements.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Elements/Elements.swift rename to Sources/HTMLKit/Framework/Primitives/Elements/Elements.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Layouts/Layouts.swift b/Sources/HTMLKit/Framework/Primitives/Layouts/Layouts.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Layouts/Layouts.swift rename to Sources/HTMLKit/Framework/Primitives/Layouts/Layouts.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Nodes/Node.swift b/Sources/HTMLKit/Framework/Primitives/Nodes/Node.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Nodes/Node.swift rename to Sources/HTMLKit/Framework/Primitives/Nodes/Node.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Nodes/Nodes.swift b/Sources/HTMLKit/Framework/Primitives/Nodes/Nodes.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Nodes/Nodes.swift rename to Sources/HTMLKit/Framework/Primitives/Nodes/Nodes.swift diff --git a/Sources/HTMLKit/Framework/Core/Primitives/Shared/Content.swift b/Sources/HTMLKit/Framework/Primitives/Shared/Content.swift similarity index 100% rename from Sources/HTMLKit/Framework/Core/Primitives/Shared/Content.swift rename to Sources/HTMLKit/Framework/Primitives/Shared/Content.swift diff --git a/Sources/HTMLKit/Framework/README.md b/Sources/HTMLKit/Framework/README.md new file mode 100644 index 00000000..7ec64b69 --- /dev/null +++ b/Sources/HTMLKit/Framework/README.md @@ -0,0 +1,17 @@ +# Framework + +This directory contains sources for + +### Builders + +### Environment + +### Extensions + +### Helpers + +### Localization + +### Primitives + +### Rendering diff --git a/Sources/HTMLKitComponents/Components/Card.swift b/Sources/HTMLKitComponents/Components/Card.swift index 48599fad..4e8ace51 100644 --- a/Sources/HTMLKitComponents/Components/Card.swift +++ b/Sources/HTMLKitComponents/Components/Card.swift @@ -33,6 +33,14 @@ public class Card: View { self.classes = ["card"] } + /// Creates a card. + internal init(header: [Content]?, content: [Content], classes: [String]) { + + self.header = header + self.content = content + self.classes = classes + } + public var body: Content { Division { Division { diff --git a/Sources/HTMLKitComponents/Components/Dropdown.swift b/Sources/HTMLKitComponents/Components/Dropdown.swift index f2e30457..53ef62ff 100644 --- a/Sources/HTMLKitComponents/Components/Dropdown.swift +++ b/Sources/HTMLKitComponents/Components/Dropdown.swift @@ -25,6 +25,14 @@ public struct Dropdown: View { self.classes = ["dropdown"] } + /// Creates a dropdown. + internal init(label: [Content], content: [Content], classes: [String]) { + + self.label = label + self.content = content + self.classes = classes + } + public var body: Content { Division { Division { diff --git a/Sources/HTMLKitComponents/Components/Modal.swift b/Sources/HTMLKitComponents/Components/Modal.swift index d248ba13..61e709ec 100644 --- a/Sources/HTMLKitComponents/Components/Modal.swift +++ b/Sources/HTMLKitComponents/Components/Modal.swift @@ -26,6 +26,15 @@ public struct Modal: View, Modifiable, Actionable { self.classes = ["modal"] } + /// Createsa model. + internal init(content: [Content], classes: [String], events: [String]?, id: String?) { + + self.content = content + self.classes = classes + self.events = events + self.id = id + } + public var body: Content { Dialog { content diff --git a/Sources/HTMLKitComponents/Components/ScrollView.swift b/Sources/HTMLKitComponents/Components/ScrollView.swift index a1dfc723..e9e98785 100644 --- a/Sources/HTMLKitComponents/Components/ScrollView.swift +++ b/Sources/HTMLKitComponents/Components/ScrollView.swift @@ -21,6 +21,13 @@ public struct ScrollView: View { self.classes = ["scrollview", direction.rawValue] } + /// Creates a scrollview + internal init(content: [Content], classes: [String]) { + + self.content = content + self.classes = classes + } + public var body: Content { Division { content diff --git a/Sources/HTMLKitComponents/Events.swift b/Sources/HTMLKitComponents/Events.swift index 06c48f15..93374b6a 100644 --- a/Sources/HTMLKitComponents/Events.swift +++ b/Sources/HTMLKitComponents/Events.swift @@ -102,7 +102,7 @@ public enum Events { return """ $('#\(selector)').onSubmit(function() { \(script) - }) + }); """ } } From 4636e9a3492df1ab56e69653f3a38b31366419e1 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 26 Feb 2023 12:08:07 +0100 Subject: [PATCH 26/29] Add form validation --- Sources/HTMLKitComponents/Actions.swift | 31 ++++++++++ .../HTMLKitComponents/Components/Form.swift | 9 ++- Sources/HTMLKitComponents/Events.swift | 10 +++- .../Modifiers/FormModifier.swift | 4 +- Sources/HTMLKitComponents/Resources/js/all.js | 58 +++++++++++++++++++ Sources/HTMLKitComponents/Validator.swift | 36 ++++++++++++ 6 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 Sources/HTMLKitComponents/Validator.swift diff --git a/Sources/HTMLKitComponents/Actions.swift b/Sources/HTMLKitComponents/Actions.swift index 5a7b6d48..f4d19532 100644 --- a/Sources/HTMLKitComponents/Actions.swift +++ b/Sources/HTMLKitComponents/Actions.swift @@ -3,6 +3,8 @@ The file contains the action stencils for the components. */ +import Foundation + /// A collection of actions, that can be triggered by events. public enum Actions { @@ -21,6 +23,19 @@ public enum Actions { /// Closes the target. case close(_ target: String) + /// Validates the form. + case valdiate(_ target: String, _ rules: [Validator]) + + public var description: String { + + switch self { + case .valdiate(_, _): + return "validate" + default: + return "default" + } + } + /// The script for the action. public var script: String { @@ -39,6 +54,9 @@ public enum Actions { case .close(let target): return close(target) + + case .valdiate(let target, let rules): + return validate(target, rules) } } @@ -66,4 +84,17 @@ public enum Actions { private func close(_ target: String) -> String { return "$('#\(target)').close();" } + + /// Returns a close action stencil. + private func validate(_ target: String, _ validators: [Validator]) -> String { + + if let data = try? JSONEncoder().encode(validators) { + + if let result = String(data: data, encoding: .utf8) { + return "$('#\(target)').validate('\(result)');" + } + } + + return "$('#\(target)').validate('[]');" + } } diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index a49b09ab..ee630cde 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -63,8 +63,13 @@ public struct Form: View, Actionable { extension Form: FormModifier { - public func onSubmit(perfom action: Actions) -> Form { - return self.mutate(submitevent: action.script) + public func onSubmit(perfom action: Actions) -> Form { + + if action.description == "validate" { + return self.mutate(submitevent: action.script, validation: true) + } + + return self.mutate(submitevent: action.script, validation: false) } } diff --git a/Sources/HTMLKitComponents/Events.swift b/Sources/HTMLKitComponents/Events.swift index 93374b6a..66bc6627 100644 --- a/Sources/HTMLKitComponents/Events.swift +++ b/Sources/HTMLKitComponents/Events.swift @@ -3,6 +3,8 @@ The file contains the event stencils for the components. */ +import Foundation + /// A collection of events, that can occur on components. public enum Events { @@ -97,12 +99,16 @@ public enum Events { } /// Returns a submit event stencil. - static func submit(selector: String, script: String) -> String { + static func submit(selector: String, script: String, validation: Bool) -> String { return """ $('#\(selector)').onSubmit(function() { + + event.preventDefault(); + \(script) - }); + + }, \(validation)); """ } } diff --git a/Sources/HTMLKitComponents/Modifiers/FormModifier.swift b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift index 5733c7b6..3aac43a1 100644 --- a/Sources/HTMLKitComponents/Modifiers/FormModifier.swift +++ b/Sources/HTMLKitComponents/Modifiers/FormModifier.swift @@ -12,12 +12,12 @@ public protocol FormModifier { extension FormModifier where Self: Actionable { - internal func mutate(submitevent script: String) -> Self { + internal func mutate(submitevent script: String, validation: Bool) -> Self { guard let identifier = self.id else { fatalError("Initiative identifier unkown.") } - return self.mutate(event: Events.submit(selector: identifier, script: script)) + return self.mutate(event: Events.submit(selector: identifier, script: script, validation: validation)) } } diff --git a/Sources/HTMLKitComponents/Resources/js/all.js b/Sources/HTMLKitComponents/Resources/js/all.js index 39e80823..3f4013f9 100644 --- a/Sources/HTMLKitComponents/Resources/js/all.js +++ b/Sources/HTMLKitComponents/Resources/js/all.js @@ -82,6 +82,10 @@ var $ = (function () { * Performs when the target is submitted. */ constructor.prototype.onSubmit = function (callback) { + + if (validate) { + this.elems[0].setAttribute("novalidate", "novalidate"); + } this.elems[0].addEventListener("submit", callback); }; @@ -132,6 +136,60 @@ var $ = (function () { this.elems[0].close() }; + /** + * Validates a form. + */ + constructor.prototype.validate = function(validators) { + + const form = this.elems[0]; + + for (let validator of JSON.parse(validators)) { + + const element = form.elements[validator.field]; + + switch (validator.rule) { + + case "value": + + if (!element.value) { + element.setCustomValidity('The field must have a value.'); + + } else { + element.setCustomValidity(''); + } + + break; + + case "email": + + if (!element.value.includes("@")) { + element.setCustomValidity('The field must have a valid email format.'); + + } else { + element.setCustomValidity(''); + } + + break; + + case "url": + + if (!element.value.includes(":")) { + element.setCustomValidity('The field must have a valid url format.'); + + } else { + element.setCustomValidity(''); + } + } + } + + if (!form.checkValidity()) { + form.reportValidity(); + + } else { + form.submit(); + } + }; + var instantiate = function (selector) { return new constructor(selector); }; diff --git a/Sources/HTMLKitComponents/Validator.swift b/Sources/HTMLKitComponents/Validator.swift new file mode 100644 index 00000000..1f9628a0 --- /dev/null +++ b/Sources/HTMLKitComponents/Validator.swift @@ -0,0 +1,36 @@ +import Foundation + +/// The validator for the form validation. +public struct Validator: Encodable { + + public enum Rule: String { + + /// The field must have a value. + case value = "value" + + /// The field must have a valid email format. + case email = "email" + + /// The field must have a valid number format. + case number = "number" + + /// The field must have a valid date format. + case date = "date" + + /// The field must have a valid url format. + case ulr = "url" + } + + /// The name of the field. + public var field: String + + /// The rule of validation. + public var rule: String + + /// Initiates a validator. + public init(field: String, rule: Rule) { + + self.field = field + self.rule = rule.rawValue + } +} From 94ddff066a5ccfb5ccf951a0fb91624ca8b67486 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Sun, 26 Feb 2023 13:51:28 +0100 Subject: [PATCH 27/29] Fix some sort of things --- Package.swift | 3 +- .../HTMLKitComponents/Resources/css/form.css | 5 ++- Sources/HTMLKitComponents/Resources/js/all.js | 36 +++++++++---------- .../Resources/js/carousel.js | 2 +- Sources/HTMLKitComponents/Validator.swift | 7 +++- Sources/HTMLKitVapor/Environment.swift | 2 +- Sources/HTMLKitVapor/Localization.swift | 2 +- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Package.swift b/Package.swift index d97ee005..c80cdbac 100644 --- a/Package.swift +++ b/Package.swift @@ -33,7 +33,8 @@ let package = Package( dependencies: [ .product(name: "Lingo", package: "Lingo"), .product(name: "Collections", package: "swift-collections") - ] + ], + exclude: ["Abstraction/README.md", "Framework/README.md"] ), .target( name: "HTMLKitConverter", diff --git a/Sources/HTMLKitComponents/Resources/css/form.css b/Sources/HTMLKitComponents/Resources/css/form.css index 7e537a9d..1db797af 100644 --- a/Sources/HTMLKitComponents/Resources/css/form.css +++ b/Sources/HTMLKitComponents/Resources/css/form.css @@ -141,7 +141,6 @@ -webkit-appearance: none; } -.required\:true:after { - content: " *"; - color: var(--redColor); +.input:invalid { + border: 1px solid red !important; } diff --git a/Sources/HTMLKitComponents/Resources/js/all.js b/Sources/HTMLKitComponents/Resources/js/all.js index 3f4013f9..f6ee7b4c 100644 --- a/Sources/HTMLKitComponents/Resources/js/all.js +++ b/Sources/HTMLKitComponents/Resources/js/all.js @@ -2,14 +2,14 @@ var $ = (function () { 'use strict'; - var constructor = function (selector) { + var Self = function (selector) { this.elems = document.querySelectorAll(selector); }; /** * Peforms when the pointer enters the target area. */ - constructor.prototype.onHover = function (callback) { + Self.prototype.onHover = function (callback) { this.elems[0].addEventListener("mouseenter", callback); }; @@ -17,7 +17,7 @@ var $ = (function () { /** * Peforms when the pointer leaves the target area. */ - constructor.prototype.onLeave = function (callback) { + Self.prototype.onLeave = function (callback) { this.elems[0].addEventListener("mouseleave", callback); }; @@ -25,7 +25,7 @@ var $ = (function () { /** * Performs when the target value changes. */ - constructor.prototype.onChange = function (callback) { + Self.prototype.onChange = function (callback) { this.elems[0].addEventListener("change", callback); }; @@ -33,7 +33,7 @@ var $ = (function () { /** * Performs when the target is clicked. */ - constructor.prototype.onClick = function (callback) { + Self.prototype.onClick = function (callback) { this.elems[0].addEventListener("click", callback); }; @@ -41,7 +41,7 @@ var $ = (function () { /** * Performs when the target is touched. */ - constructor.prototype.onTapGesture = function (callback) { + Self.prototype.onTapGesture = function (callback) { this.elems[0].addEventListener("touchend", callback); }; @@ -49,7 +49,7 @@ var $ = (function () { /** * Performs when the target is touched. */ - constructor.prototype.onLongPressGesture = function (callback) { + Self.prototype.onLongPressGesture = function (callback) { this.elems[0].addEventListener("touchstart", callback); }; @@ -57,7 +57,7 @@ var $ = (function () { /** * Performs when the target is dragged. */ - constructor.prototype.onDrag = function (callback) { + Self.prototype.onDrag = function (callback) { this.elems[0].addEventListener("drag", callback); }; @@ -65,7 +65,7 @@ var $ = (function () { /** * Performs when the target is dropped. */ - constructor.prototype.onDrop = function (callback) { + Self.prototype.onDrop = function (callback) { this.elems[0].addEventListener("drop", callback); }; @@ -73,7 +73,7 @@ var $ = (function () { /** * Performs when the target is focused. */ - constructor.prototype.onFocus = function (callback) { + Self.prototype.onFocus = function (callback) { this.elems[0].addEventListener("focus", callback); }; @@ -81,7 +81,7 @@ var $ = (function () { /** * Performs when the target is submitted. */ - constructor.prototype.onSubmit = function (callback) { + Self.prototype.onSubmit = function (callback) { if (validate) { this.elems[0].setAttribute("novalidate", "novalidate"); @@ -93,7 +93,7 @@ var $ = (function () { /** * Shows the target. */ - constructor.prototype.show = function() { + Self.prototype.show = function() { const elements = document.getElementsByClassName("state:visible"); @@ -107,7 +107,7 @@ var $ = (function () { /** * Hides the target. */ - constructor.prototype.hide = function() { + Self.prototype.hide = function() { this.elems[0].classList.add("state:hidden") }; @@ -115,7 +115,7 @@ var $ = (function () { /** * Animates the target. */ - constructor.prototype.animate = function({params}, speed) { + Self.prototype.animate = function({params}, speed) { this.elems[0].animate({params}, speed); }; @@ -123,7 +123,7 @@ var $ = (function () { /** * Opens the dialog. */ - constructor.prototype.open = function() { + Self.prototype.open = function() { this.elems[0].showModal() }; @@ -131,7 +131,7 @@ var $ = (function () { /** * Closes the dialog. */ - constructor.prototype.close = function() { + Self.prototype.close = function() { this.elems[0].close() }; @@ -139,7 +139,7 @@ var $ = (function () { /** * Validates a form. */ - constructor.prototype.validate = function(validators) { + Self.prototype.validate = function(validators) { const form = this.elems[0]; @@ -191,7 +191,7 @@ var $ = (function () { }; var instantiate = function (selector) { - return new constructor(selector); + return new Self(selector); }; return instantiate; diff --git a/Sources/HTMLKitComponents/Resources/js/carousel.js b/Sources/HTMLKitComponents/Resources/js/carousel.js index 602fd37b..b7b01cd6 100644 --- a/Sources/HTMLKitComponents/Resources/js/carousel.js +++ b/Sources/HTMLKitComponents/Resources/js/carousel.js @@ -2,7 +2,7 @@ var Carousel = (function () { 'use strict'; - function Self(element) { + function Self() { this.element = document.getElementsByClassName('carousel-content')[0]; this.slides = document.getElementsByClassName('slide'); diff --git a/Sources/HTMLKitComponents/Validator.swift b/Sources/HTMLKitComponents/Validator.swift index 1f9628a0..6b74e4b3 100644 --- a/Sources/HTMLKitComponents/Validator.swift +++ b/Sources/HTMLKitComponents/Validator.swift @@ -1,3 +1,8 @@ +/* + Abstract: + The file contains the validator for the form validation. + */ + import Foundation /// The validator for the form validation. @@ -18,7 +23,7 @@ public struct Validator: Encodable { case date = "date" /// The field must have a valid url format. - case ulr = "url" + case url = "url" } /// The name of the field. diff --git a/Sources/HTMLKitVapor/Environment.swift b/Sources/HTMLKitVapor/Environment.swift index 9f890f5d..e37342d9 100644 --- a/Sources/HTMLKitVapor/Environment.swift +++ b/Sources/HTMLKitVapor/Environment.swift @@ -13,7 +13,7 @@ final public class Environment { internal var manager: Manager /// Initiates a environment - internal init() { + public init() { self.manager = Manager() } diff --git a/Sources/HTMLKitVapor/Localization.swift b/Sources/HTMLKitVapor/Localization.swift index 38dd4a15..b88d7e3a 100644 --- a/Sources/HTMLKitVapor/Localization.swift +++ b/Sources/HTMLKitVapor/Localization.swift @@ -34,7 +34,7 @@ public class Localization { } /// Creates a configuration - internal init() { + public init() { self.defaultDirectory = "Resources/Localization" self.defaultLocale = "en" From a65e44052912355883061301d317e2e0a49d4dc1 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 27 Feb 2023 21:50:53 +0100 Subject: [PATCH 28/29] Change the js initialization for the carousel component --- .../Components/Carousel.swift | 3 - .../Resources/js/carousel.js | 66 +++++++++++-------- .../ComponentTests.swift | 5 +- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Sources/HTMLKitComponents/Components/Carousel.swift b/Sources/HTMLKitComponents/Components/Carousel.swift index 5e591017..c3c484e0 100644 --- a/Sources/HTMLKitComponents/Components/Carousel.swift +++ b/Sources/HTMLKitComponents/Components/Carousel.swift @@ -46,9 +46,6 @@ public struct Carousel: View { .class("carousel-indication") } .class(classes.joined(separator: " ")) - Script { - "new Carousel();" - } } } diff --git a/Sources/HTMLKitComponents/Resources/js/carousel.js b/Sources/HTMLKitComponents/Resources/js/carousel.js index b7b01cd6..2a7137c7 100644 --- a/Sources/HTMLKitComponents/Resources/js/carousel.js +++ b/Sources/HTMLKitComponents/Resources/js/carousel.js @@ -1,84 +1,92 @@ -var Carousel = (function () { +(function() { - 'use strict'; - - function Self() { + var Carousel = function (element) { - this.element = document.getElementsByClassName('carousel-content')[0]; - this.slides = document.getElementsByClassName('slide'); - this.indicators = document.getElementsByClassName('indicator'); + this.element = element; + this.slides = element.getElementsByClassName('carousel-content')[0]; + this.indication = element.getElementsByClassName('carousel-indication')[0]; this.toggleState(0); - this.initiateAutoplay(1); + this.autoPlay(1); this.initiateListener(); } - Self.prototype.initiateListener = function () { + Carousel.prototype.initiateListener = function () { var self = this; - for (let indicator of this.indicators) { + for (let indicator of this.indication.children) { indicator.addEventListener('click', function (event) { event.preventDefault(); self.slideTo(self.getPosition(event.target.getAttribute('href').replace('#', ''))); + }); } }; - Self.prototype.initiateAutoplay = function (position) { + Carousel.prototype.autoPlay = function (position) { var self = this; - setInterval(function() { + setInterval(function () { - if (position < self.slides.length) { - + if (position < self.slides.children.length) { + self.slideTo(position); - + position += 1; } else { position = 0; } - }, 7000); - } + }; - Self.prototype.getPosition = function (name) { - - for(var position = 0; position < this.slides.length; position++) { + Carousel.prototype.getPosition = function (name) { + + for(var position = 0; position < this.slides.children.length; position++) { - if (this.slides[position].id == name) { + if (this.slides.children[position].id == name) { return position; } } }; - Self.prototype.toggleState = function (position) { + Carousel.prototype.toggleState = function (position) { - for(let indicator of this.indicators) { + for(let indicator of this.indication.children) { indicator.classList.remove('state:active'); } - this.indicators[position].classList.add('state:active'); + this.indication.children[position].classList.add('state:active'); }; - Self.prototype.slideTo = function (position) { + Carousel.prototype.slideTo = function (position) { var self = this; - this.element.scrollTo({ - left: (position * this.slides[position].offsetWidth) + this.slides.scrollTo({ + left: (position * this.slides.children[position].offsetWidth), behavior: 'smooth' }); self.toggleState(position); }; - return Self; + var carousel = document.getElementsByClassName('carousel'); + + if(carousel.length > 0) { + + for(var i = 0; i < carousel.length; i++) { + + (function(i) { + new Carousel(carousel[i]); + })(i); + } + } -})(); +}()); diff --git a/Tests/HTMLKitComponentsTests/ComponentTests.swift b/Tests/HTMLKitComponentsTests/ComponentTests.swift index 860e8a74..75e8469a 100644 --- a/Tests/HTMLKitComponentsTests/ComponentTests.swift +++ b/Tests/HTMLKitComponentsTests/ComponentTests.swift @@ -433,10 +433,7 @@ final class ComponentTests: XCTestCase { \ - + """ ) } From e2f13af5d7f81d4cc257d0e1fef6df7ab6f79605 Mon Sep 17 00:00:00 2001 From: Mattes Mohr Date: Mon, 27 Feb 2023 22:01:26 +0100 Subject: [PATCH 29/29] Add a textpad component --- .../HTMLKitComponents/Components/Form.swift | 69 +++++++++++++++++++ .../HTMLKitComponents/Resources/js/textpad.js | 67 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 Sources/HTMLKitComponents/Resources/js/textpad.js diff --git a/Sources/HTMLKitComponents/Components/Form.swift b/Sources/HTMLKitComponents/Components/Form.swift index ee630cde..51093492 100644 --- a/Sources/HTMLKitComponents/Components/Form.swift +++ b/Sources/HTMLKitComponents/Components/Form.swift @@ -736,3 +736,72 @@ public struct Progress: View { .class(classes.joined(separator: " ")) } } + +/// A component to edit and format text content. +public struct TextPad: View { + + /// The identifier of the textpad. + internal let name: String + + /// The content of the textpad. + internal var content: [String] + + /// The classes of the textpad. + internal var classes: [String] + + /// Creates a textpad + public init(name: String, @ContentBuilder content: () -> [String]) { + + self.name = name + self.content = content() + self.classes = ["textpad"] + } + + /// Creates a textpad. + internal init(name: String, content: [String], classes: [String]) { + + self.name = name + self.content = content + self.classes = classes + } + + public var body: Content { + Division { + UnorderedList { + ListItem { + Paragraph { + "B" + } + } + .class("toolbar-tool command:bold") + ListItem { + Paragraph { + "I" + } + } + .class("toolbar-tool command:italic") + ListItem { + Paragraph { + "U" + } + } + .class("toolbar-tool command:underline") + ListItem { + Paragraph { + "S" + } + } + .class("toolbar-tool command:strikethrough") + } + .class("textpad-toolbar") + TextArea { + content + } + .id(name) + .name(name) + .rows(5) + .class("textpad-content") + } + .class(classes.joined(separator: " ")) + } +} diff --git a/Sources/HTMLKitComponents/Resources/js/textpad.js b/Sources/HTMLKitComponents/Resources/js/textpad.js new file mode 100644 index 00000000..4b37a2df --- /dev/null +++ b/Sources/HTMLKitComponents/Resources/js/textpad.js @@ -0,0 +1,67 @@ +(function() { + + var Textpad = function (element) { + + this.element = element + this.content = element.getElementsByClassName('textpad-content')[0]; + this.toolbar = element.getElementsByClassName('textpad-toolbar')[0]; + + this.initiateListener(); + }; + + Textpad.prototype.initiateListener = function () { + + var self = this; + + for (let tool of this.toolbar.children) { + + tool.addEventListener('click', function (event) { + + event.preventDefault(); + + var replacement = ""; + + var selection = self.getSelection(); + + if (tool.classList.contains('command:bold')) { + replacement = '' + selection + ''; + } + + if (tool.classList.contains('command:italic')) { + replacement = '' + selection + ''; + } + + if (tool.classList.contains('command:underline')) { + replacement = '' + selection + ''; + } + + if (tool.classList.contains('command:strikethrough')) { + replacement = '' + selection + ''; + } + + self.content.setRangeText(replacement, self.content.selectionStart, self.content.selectionEnd); + }); + } + }; + + Textpad.prototype.getSelection = function () { + + return this.content.value.substring(this.content.selectionStart, this.content.selectionEnd); + }; + + var textpad = document.getElementsByClassName('textpad'); + + if(textpad.length > 0) { + + for(var i = 0; i < textpad.length; i++) { + + (function(i) { + + new Textpad(textpad[i]); + + })(i); + + } + } + +}());