diff options
author | HJ <thechairman@thechairman.info> | 2024-02-03 15:09:54 -0500 |
---|---|---|
committer | HJ <thechairman@thechairman.info> | 2024-02-03 15:09:54 -0500 |
commit | 96a3c5c179d8d3fff24eb2953e45f8dd15e2714c (patch) | |
tree | 0a67bc0cfeabe51740bb049c61f16f1ac3bdd4ff /aoc2023/build/packages/gleam_community_colour | |
parent | 547fe03cf43105f46160e2dd9afff21637eaaf47 (diff) | |
download | gleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.tar.gz gleam_aoc-96a3c5c179d8d3fff24eb2953e45f8dd15e2714c.zip |
cleanup
Diffstat (limited to 'aoc2023/build/packages/gleam_community_colour')
10 files changed, 2131 insertions, 0 deletions
diff --git a/aoc2023/build/packages/gleam_community_colour/LICENCE b/aoc2023/build/packages/gleam_community_colour/LICENCE new file mode 100644 index 0000000..a84f0ec --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/LICENCE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2023 Gleam Community Contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
\ No newline at end of file diff --git a/aoc2023/build/packages/gleam_community_colour/README.md b/aoc2023/build/packages/gleam_community_colour/README.md new file mode 100644 index 0000000..0eccdd7 --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/README.md @@ -0,0 +1,36 @@ +# gleam-community/colour + +A package for a standard Colour type, conversions, and other utilities. + +[](https://hex.pm/packages/gleam_community_colour) +[](https://hexdocs.pm/gleam_community_colour/) + +✨ This project is written in pure Gleam so you can use it anywhere Gleam runs: Erlang, Elixir, Node, Deno, and the browser! + +--- + +## Quickstart + +```gleam +import gleam_community/colour +import gleam_community/colour/accessibility + +pub fn main() { + let foreground = colour.from_hsl(h: 0.858, s: 1.0, l: 0.843) + + let background_options = [colour.light_grey, colour.dark_grey] + + let background = accessibility.maximum_contrast(foreground, background_options) +} +``` + +## Installation + +`gleam_community` packages are published to [hex.pm](https://hex.pm/packages/gleam_community_colour) +with the prefix `gleam_community_`. You can add them to your Gleam projects directly: + +```sh +gleam add gleam_community_colour +``` + +The docs can be found over at [hexdocs.pm](https://hexdocs.pm/gleam_community_colour). diff --git a/aoc2023/build/packages/gleam_community_colour/gleam.toml b/aoc2023/build/packages/gleam_community_colour/gleam.toml new file mode 100644 index 0000000..07a81bf --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/gleam.toml @@ -0,0 +1,11 @@ +name = "gleam_community_colour" +version = "1.2.0" +licences = ["Apache-2.0"] +description = "Colour types, conversions, and other utilities" +repository = { type = "github", user = "gleam-community", repo = "colour" } + +[dependencies] +gleam_stdlib = "~> 0.32" + +[dev-dependencies] +gleeunit = "~> 0.11" diff --git a/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl new file mode 100644 index 0000000..06116df --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl @@ -0,0 +1 @@ +-record(hsla, {h :: float(), s :: float(), l :: float(), a :: float()}). diff --git a/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl new file mode 100644 index 0000000..fff139e --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl @@ -0,0 +1 @@ +-record(rgba, {r :: float(), g :: float(), b :: float(), a :: float()}). diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam new file mode 100644 index 0000000..1f5872f --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour.gleam @@ -0,0 +1,1126 @@ +//// +//// - **Types** +//// - [`Colour`](#Colour) +//// - [`Color`](#Color) +//// - **Constructors** +//// - [`from_rgb255`](#from_rgb255) +//// - [`from_rgb`](#from_rgb) +//// - [`from_rgba`](#from_rgba) +//// - [`from_hsl`](#from_hsl) +//// - [`from_hsla`](#from_hsla) +//// - [`from_rgb_hex`](#from_rgb_hex) +//// - [`from_rgba_hex`](#from_rgba_hex) +//// - [`from_rgb_hex_string`](#from_rgb_hex_string) +//// - [`from_rgba_hex_string`](#from_rgba_hex_string) +//// - **Conversions** +//// - [`to_rgba`](#to_rgba) +//// - [`to_hsla`](#hsla) +//// - [`to_css_rgba_string`](#to_css_rgba_string) +//// - [`to_rgba_hex_string`](#to_rgba_hex_string) +//// - [`to_rgb_hex_string`](#to_rgb_hex_string) +//// - [`to_rgba_hex`](#to_rgba_hex) +//// - [`to_rgb_hex`](#to_rgb_hex) +//// - **Colours** +//// - [`light_red`](#light_red) +//// - [`red`](#red) +//// - [`dark_red`](#dark_red) +//// - [`light_orange`](#light_orange) +//// - [`orange`](#orange) +//// - [`dark_orange`](#dark_orange) +//// - [`light_yellow`](#light_yellow) +//// - [`yellow`](#yellow) +//// - [`dark_yellow`](#dark_yellow) +//// - [`light_green`](#light_green) +//// - [`green`](#green) +//// - [`dark_green`](#dark_green) +//// - [`light_blue`](#light_blue) +//// - [`blue`](#blue) +//// - [`dark_blue`](#dark_blue) +//// - [`light_purple`](#light_purple) +//// - [`purple`](#purple) +//// - [`dark_purple`](#dark_purple) +//// - [`light_brown`](#light_brown) +//// - [`brown`](#brown) +//// - [`dark_brown`](#dark_brown) +//// - [`black`](#black) +//// - [`white`](#white) +//// - [`light_grey`](#light_grey) +//// - [`grey`](#grey) +//// - [`dark_grey`](#dark_grey) +//// - [`light_gray`](#light_gray) +//// - [`gray`](#gray) +//// - [`dark_gray`](#dark_gray) +//// - [`light_charcoal`](#light_charcoal) +//// - [`charcoal`](#charcoal) +//// - [`dark_charcoal`](#dark_charcoal) +//// - [`pink`](#pink) +//// +//// --- +//// +//// This package was heavily inspired by the `elm-color` module. +//// The original source code can be found +//// <a href="https://github.com/avh4/elm-color/">here</a>. +//// +//// <details> +//// <summary>The license of that package is produced below:</summary> +//// +//// +//// > MIT License +//// +//// > Copyright 2018 Aaron VonderHaar +//// +//// > Redistribution and use in source and binary forms, with or without modification, +//// are permitted provided that the following conditions are met: +//// +//// 1. Redistributions of source code must retain the above copyright notice, +//// this list of conditions and the following disclaimer. +//// +//// 2. Redistributions in binary form must reproduce the above copyright notice, +//// this list of conditions and the following disclaimer in the documentation +//// and/or other materials provided with the distribution. +//// +//// 3. Neither the name of the copyright holder nor the names of its contributors +//// may be used to endorse or promote products derived from this software without +//// specific prior written permission. +//// +//// > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +//// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +//// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +//// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +//// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +//// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +//// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//// +//// > The above copyright notice and this permission notice shall be included in all +//// copies or substantial portions of the Software. +//// </details> +//// + +// Just in case we decide in the future to no longer include the above reference +// and license, this package was initially a port of the `elm-color` module: +// +// https://github.com/avh4/elm-color/ +// + +// IMPORTS -------------------------------------------------------------------- + +import gleam/int +import gleam/float +import gleam/result +import gleam/string +import gleam/list + +// TYPES ---------------------------------------------------------------------- + +/// A representation of a colour that can be converted to RGBA or HSLA format. +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// </br> +/// +pub opaque type Colour { + Rgba(r: Float, g: Float, b: Float, a: Float) + Hsla(h: Float, s: Float, l: Float, a: Float) +} + +/// Type alias for `Colour` +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// </br> +/// +pub type Color = + Colour + +// UTILITY -------------------------------------------------------------------- + +fn valid_colour_value(c: Float) -> Result(Float, Nil) { + case c >. 1.0 || c <. 0.0 { + True -> Error(Nil) + False -> Ok(c) + } +} + +fn hue_to_rgb(hue: Float, m1: Float, m2: Float) -> Float { + let h = case hue { + _ if hue <. 0.0 -> hue +. 1.0 + _ if hue >. 1.0 -> hue -. 1.0 + _ -> hue + } + + let h_t_6 = h *. 6.0 + let h_t_2 = h *. 2.0 + let h_t_3 = h *. 3.0 + + case h { + _ if h_t_6 <. 1.0 -> m1 +. { m2 -. m1 } *. h *. 6.0 + _ if h_t_2 <. 1.0 -> m2 + _ if h_t_3 <. 2.0 -> m1 +. { m2 -. m1 } *. { 2.0 /. 3.0 -. h } *. 6.0 + _ -> m1 + } +} + +fn hex_string_to_int(hex_string: String) -> Result(Int, Nil) { + let hex = case hex_string { + "#" <> hex_number -> hex_number + "0x" <> hex_number -> hex_number + _ -> hex_string + } + + hex + |> string.lowercase() + |> string.to_graphemes() + |> list.reverse() + |> list.index_fold( + Ok(0), + fn(total, char, index) { + case total { + Error(Nil) -> Error(Nil) + Ok(v) -> { + use num <- result.then(case char { + "a" -> Ok(10) + "b" -> Ok(11) + "c" -> Ok(12) + "d" -> Ok(13) + "e" -> Ok(14) + "f" -> Ok(15) + _ -> int.parse(char) + }) + use base <- result.then(int.power(16, int.to_float(index))) + Ok(v + float.round(int.to_float(num) *. base)) + } + } + }, + ) +} + +fn hsla_to_rgba( + h: Float, + s: Float, + l: Float, + a: Float, +) -> #(Float, Float, Float, Float) { + let m2 = case l <=. 0.5 { + True -> l *. { s +. 1.0 } + False -> l +. s -. l *. s + } + + let m1 = l *. 2.0 -. m2 + + let r = hue_to_rgb(h +. 1.0 /. 3.0, m1, m2) + let g = hue_to_rgb(h, m1, m2) + let b = hue_to_rgb(h -. 1.0 /. 3.0, m1, m2) + + #(r, g, b, a) +} + +fn rgba_to_hsla( + r: Float, + g: Float, + b: Float, + a: Float, +) -> #(Float, Float, Float, Float) { + let min_colour = float.min(r, float.min(g, b)) + + let max_colour = float.max(r, float.max(g, b)) + + let h1 = case True { + _ if max_colour == r -> float.divide(g -. b, max_colour -. min_colour) + _ if max_colour == g -> + float.divide(b -. r, max_colour -. min_colour) + |> result.then(fn(d) { Ok(2.0 +. d) }) + _ -> + float.divide(r -. g, max_colour -. min_colour) + |> result.then(fn(d) { Ok(4.0 +. d) }) + } + + let h2 = case h1 { + Ok(v) -> Ok(v *. { 1.0 /. 6.0 }) + _ -> h1 + } + + let h3 = case h2 { + Ok(v) if v <. 0.0 -> v +. 1.0 + Ok(v) -> v + _ -> 0.0 + } + + let l = { min_colour +. max_colour } /. 2.0 + + let s = case True { + _ if min_colour == max_colour -> 0.0 + _ if l <. 0.5 -> + { max_colour -. min_colour } /. { max_colour +. min_colour } + _ -> { max_colour -. min_colour } /. { 2.0 -. max_colour -. min_colour } + } + + #(h3, s, l, a) +} + +// CONSTRUCTORS --------------------------------------------------------------- + +/// Returns a `Result(Colour)` created from the given 8 bit RGB values. +/// +/// Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb255(255, 0, 0) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgb255(r red: Int, g green: Int, b blue: Int) -> Result(Colour, Nil) { + use r <- result.then( + red + |> int.to_float() + |> float.divide(255.0) + |> result.then(valid_colour_value), + ) + + use g <- result.then( + green + |> int.to_float() + |> float.divide(255.0) + |> result.then(valid_colour_value), + ) + + use b <- result.then( + blue + |> int.to_float() + |> float.divide(255.0) + |> result.then(valid_colour_value), + ) + + Ok(Rgba(r: r, g: g, b: b, a: 1.0)) +} + +/// Returns `Result(Colour)` created from the given RGB values. +/// +/// If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)` +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb(1.0, 0.0, 0.0) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgb( + r red: Float, + g green: Float, + b blue: Float, +) -> Result(Colour, Nil) { + use r <- result.then(valid_colour_value(red)) + use g <- result.then(valid_colour_value(green)) + use b <- result.then(valid_colour_value(blue)) + + Ok(Rgba(r: r, g: g, b: b, a: 1.0)) +} + +/// Returns `Result(Colour)` created from the given RGBA values. +/// +/// Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgba( + r red: Float, + g green: Float, + b blue: Float, + a alpha: Float, +) -> Result(Colour, Nil) { + use r <- result.then(valid_colour_value(red)) + use g <- result.then(valid_colour_value(green)) + use b <- result.then(valid_colour_value(blue)) + use a <- result.then(valid_colour_value(alpha)) + + Ok(Rgba(r: r, g: g, b: b, a: a)) +} + +/// Returns `Result(Colour)` created from the given HSLA values. +/// +/// Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_hsla( + h hue: Float, + s saturation: Float, + l lightness: Float, + a alpha: Float, +) -> Result(Colour, Nil) { + use h <- result.then(valid_colour_value(hue)) + use s <- result.then(valid_colour_value(saturation)) + use l <- result.then(valid_colour_value(lightness)) + use a <- result.then(valid_colour_value(alpha)) + + Ok(Hsla(h: h, s: s, l: l, a: a)) +} + +/// Returns `Result(Colour)` created from the given HSL values. +/// +/// Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_hsla(0.0, 1.0, 0.5) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_hsl( + h hue: Float, + s saturation: Float, + l lightness: Float, +) -> Result(Colour, Nil) { + from_hsla(hue, saturation, lightness, 1.0) +} + +/// Returns a `Result(Colour)` created from the given hex `Int`. +/// +/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb_hex(0xff0000) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgb_hex(hex: Int) -> Result(Colour, Nil) { + case hex > 0xffffff || hex < 0 { + True -> Error(Nil) + False -> { + let r = + int.bitwise_shift_right(hex, 16) + |> int.bitwise_and(0xff) + let g = + int.bitwise_shift_right(hex, 8) + |> int.bitwise_and(0xff) + let b = int.bitwise_and(hex, 0xff) + from_rgb255(r, g, b) + } + } +} + +/// Returns a `Result(Colour)` created from the given RGB hex `String`. +/// +/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffff" or less than `"#0"` +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb_hex_string("#ff0000") +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgb_hex_string(hex_string: String) -> Result(Colour, Nil) { + use hex_int <- result.then(hex_string_to_int(hex_string)) + + from_rgb_hex(hex_int) +} + +/// Returns a `Result(Colour)` created from the given RGBA hex `String`. +/// +/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffffff" or less than `"#0"` +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red_half_opacity) = from_rgba_hex_string("#ff00007f") +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgba_hex_string(hex_string: String) -> Result(Colour, Nil) { + use hex_int <- result.then(hex_string_to_int(hex_string)) + + from_rgba_hex(hex_int) +} + +/// Returns a `Result(Colour)` created from the given hex `Int`. +/// +/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn from_rgba_hex(hex: Int) -> Result(Colour, Nil) { + case hex > 0xffffffff || hex < 0 { + True -> Error(Nil) + False -> { + // This won't fail because we are always dividing by 255.0 + let assert Ok(r) = + int.bitwise_shift_right(hex, 24) + |> int.bitwise_and(0xff) + |> int.to_float() + |> float.divide(255.0) + // This won't fail because we are always dividing by 255.0 + let assert Ok(g) = + int.bitwise_shift_right(hex, 16) + |> int.bitwise_and(0xff) + |> int.to_float() + |> float.divide(255.0) + // This won't fail because we are always dividing by 255.0 + let assert Ok(b) = + int.bitwise_shift_right(hex, 8) + |> int.bitwise_and(0xff) + |> int.to_float() + |> float.divide(255.0) + // This won't fail because we are always dividing by 255.0 + let assert Ok(a) = + int.bitwise_and(hex, 0xff) + |> int.to_float() + |> float.divide(255.0) + from_rgba(r, g, b, a) + } + } +} + +// CONVERSIONS ---------------------------------------------------------------- + +/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s +/// R, G, B, and A values respectively. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb255(255, 0, 0) +/// let #(r, g, b, a) = to_rgba(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_rgba(colour: Colour) -> #(Float, Float, Float, Float) { + case colour { + Rgba(r, g, b, a) -> #(r, g, b, a) + Hsla(h, s, l, a) -> hsla_to_rgba(h, s, l, a) + } +} + +/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s +/// H, S, L, and A values respectively. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb255(255, 0, 0) +/// let #(h, s, l, a) = to_hsla(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_hsla(colour: Colour) -> #(Float, Float, Float, Float) { + case colour { + Hsla(h, s, l, a) -> #(h, s, l, a) + Rgba(r, g, b, a) -> rgba_to_hsla(r, g, b, a) + } +} + +/// Returns an rgba formatted CSS `String` created from the given `Colour`. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgb255(255, 0, 0) +/// let css_red = to_css_rgba_string(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_css_rgba_string(colour: Colour) -> String { + let #(r, g, b, a) = to_rgba(colour) + + let percent = fn(x: Float) -> Float { + // This won't fail because we are always dividing by 100.0 + let assert Ok(p) = + x + |> float.multiply(10_000.0) + |> float.round() + |> int.to_float() + |> float.divide(100.0) + + p + } + + let round_to = fn(x: Float) -> Float { + // This won't fail because we are always dividing by 1000.0 + let assert Ok(r) = + x + |> float.multiply(1000.0) + |> float.round() + |> int.to_float() + |> float.divide(1000.0) + + r + } + + string.join( + [ + "rgba(", + float.to_string(percent(r)) <> "%,", + float.to_string(percent(g)) <> "%,", + float.to_string(percent(b)) <> "%,", + float.to_string(round_to(a)), + ")", + ], + "", + ) +} + +/// Returns an rgba hex formatted `String` created from the given `Colour`. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) +/// let red_hex = to_rgba_hex_string(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_rgba_hex_string(colour: Colour) -> String { + to_rgba_hex(colour) + |> int.to_base16() +} + +/// Returns an rgb hex formatted `String` created from the given `Colour`. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgba(255, 0, 0) +/// let red_hex = to_rgb_hex_string(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_rgb_hex_string(colour: Colour) -> String { + to_rgb_hex(colour) + |> int.to_base16() +} + +/// Returns an hex `Int` created from the given `Colour`. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) +/// let red_hex_int = to_rgba_hex(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_rgba_hex(colour: Colour) -> Int { + let #(r, g, b, a) = to_rgba(colour) + + let red = + r *. 255.0 + |> float.round() + |> int.bitwise_shift_left(24) + + let green = + g *. 255.0 + |> float.round() + |> int.bitwise_shift_left(16) + + let blue = + b *. 255.0 + |> float.round() + |> int.bitwise_shift_left(8) + + let alpha = + a *. 255.0 + |> float.round() + + red + green + blue + alpha +} + +/// Returns a rgb hex `Int` created from the given `Colour`. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// assert Ok(red) = from_rgba(255, 0, 0) +/// let red_hex_int = to_rgb_hex(red) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn to_rgb_hex(colour: Colour) -> Int { + let #(r, g, b, _) = to_rgba(colour) + + let red = + r *. 255.0 + |> float.round() + |> int.bitwise_shift_left(16) + + let green = + g *. 255.0 + |> float.round() + |> int.bitwise_shift_left(8) + + let blue = + b *. 255.0 + |> float.round() + + red + green + blue +} + +// COLOURS -------------------------------------------------------------------- + +/// A `Colour` reprsenting the colour RGBA(239, 41, 41, 1.0) +pub const light_red = Rgba( + r: 0.9372549019607843, + g: 0.1607843137254902, + b: 0.1607843137254902, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(204, 0, 0, 1.0) +pub const red = Rgba(r: 0.8, g: 0.0, b: 0.0, a: 1.0) + +/// A `Colour` reprsenting the colour RGBA(164, 0, 0, 1.0) +pub const dark_red = Rgba(r: 0.6431372549019608, g: 0.0, b: 0.0, a: 1.0) + +/// A `Colour` reprsenting the colour RGBA(252, 175, 62, 1.0) +pub const light_orange = Rgba( + r: 0.9882352941176471, + g: 0.6862745098039216, + b: 0.24313725490196078, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(245, 121, 0, 1.0) +pub const orange = Rgba( + r: 0.9607843137254902, + g: 0.4745098039215686, + b: 0.0, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(206, 92, 0, 1.0) +pub const dark_orange = Rgba( + r: 0.807843137254902, + g: 0.3607843137254902, + b: 0.0, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(255, 233, 79, 1.0) +pub const light_yellow = Rgba( + r: 1.0, + g: 0.9137254901960784, + b: 0.30980392156862746, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(237, 212, 0, 1.0) +pub const yellow = Rgba( + r: 0.9294117647058824, + g: 0.8313725490196079, + b: 0.0, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(196, 160, 0, 1.0) +pub const dark_yellow = Rgba( + r: 0.7686274509803922, + g: 0.6274509803921569, + b: 0.0, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(138, 226, 52, 1.0) +pub const light_green = Rgba( + r: 0.5411764705882353, + g: 0.8862745098039215, + b: 0.20392156862745098, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(115, 210, 22, 1.0) +pub const green = Rgba( + r: 0.45098039215686275, + g: 0.8235294117647058, + b: 0.08627450980392157, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(78, 154, 6, 1.0) +pub const dark_green = Rgba( + r: 0.3058823529411765, + g: 0.6039215686274509, + b: 0.023529411764705882, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(114, 159, 207, 1.0) +pub const light_blue = Rgba( + r: 0.4470588235294118, + g: 0.6235294117647059, + b: 0.8117647058823529, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(52, 101, 164, 1.0) +pub const blue = Rgba( + r: 0.20392156862745098, + g: 0.396078431372549, + b: 0.6431372549019608, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(32, 74, 135, 1.0) +pub const dark_blue = Rgba( + r: 0.12549019607843137, + g: 0.2901960784313726, + b: 0.5294117647058824, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(173, 127, 168, 1.0) +pub const light_purple = Rgba( + r: 0.6784313725490196, + g: 0.4980392156862745, + b: 0.6588235294117647, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(117, 80, 123, 1.0) +pub const purple = Rgba( + r: 0.4588235294117647, + g: 0.3137254901960784, + b: 0.4823529411764706, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(92, 53, 102, 1.0) +pub const dark_purple = Rgba( + r: 0.3607843137254902, + g: 0.20784313725490197, + b: 0.4, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(233, 185, 110, 1.0) +pub const light_brown = Rgba( + r: 0.9137254901960784, + g: 0.7254901960784313, + b: 0.43137254901960786, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(193, 125, 17, 1.0) +pub const brown = Rgba( + r: 0.7568627450980392, + g: 0.49019607843137253, + b: 0.06666666666666667, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(143, 89, 2, 1.0) +pub const dark_brown = Rgba( + r: 0.5607843137254902, + g: 0.34901960784313724, + b: 0.00784313725490196, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(0, 0, 0, 1.0) +pub const black = Rgba(r: 0.0, g: 0.0, b: 0.0, a: 1.0) + +/// A `Colour` reprsenting the colour RGBA(255, 255, 255, 1.0) +pub const white = Rgba(r: 1.0, g: 1.0, b: 1.0, a: 1.0) + +/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) +pub const light_grey = Rgba( + r: 0.9333333333333333, + g: 0.9333333333333333, + b: 0.9254901960784314, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) +pub const grey = Rgba( + r: 0.8274509803921568, + g: 0.8431372549019608, + b: 0.8117647058823529, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) +pub const dark_grey = Rgba( + r: 0.7294117647058823, + g: 0.7411764705882353, + b: 0.7137254901960784, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) +pub const light_gray = Rgba( + r: 0.9333333333333333, + g: 0.9333333333333333, + b: 0.9254901960784314, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) +pub const gray = Rgba( + r: 0.8274509803921568, + g: 0.8431372549019608, + b: 0.8117647058823529, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) +pub const dark_gray = Rgba( + r: 0.7294117647058823, + g: 0.7411764705882353, + b: 0.7137254901960784, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(136, 138, 133, 1.0) +pub const light_charcoal = Rgba( + r: 0.5333333333333333, + g: 0.5411764705882353, + b: 0.5215686274509804, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(85, 87, 83, 1.0) +pub const charcoal = Rgba( + r: 0.3333333333333333, + g: 0.3411764705882353, + b: 0.3254901960784314, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(46, 52, 54, 1.0) +pub const dark_charcoal = Rgba( + r: 0.1803921568627451, + g: 0.20392156862745098, + b: 0.21176470588235294, + a: 1.0, +) + +/// A `Colour` reprsenting the colour RGBA(255, 175, 243, 1.0) +pub const pink = Rgba( + r: 1.0, + g: 0.6862745098039216, + b: 0.9529411764705882, + a: 1.0, +) diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam new file mode 100644 index 0000000..54f75e4 --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam @@ -0,0 +1,173 @@ +//// +//// - **Accessibility** +//// - [`luminance`](#luminance) +//// - [`contrast_ratio`](#contrast_ratio) +//// - [`maximum_contrast`](#maximum_contrast) +//// +//// --- +//// +//// This package was heavily inspired by the `elm-color-extra` module. +//// The original source code can be found +//// <a href="https://github.com/noahzgordon/elm-color-extra">here</a>. +//// +//// <details> +//// <summary>The license of that package is produced below:</summary> +//// +//// +//// > MIT License +//// +//// > Copyright (c) 2016 Andreas Köberle +//// +//// > Permission is hereby granted, free of charge, to any person obtaining a copy +//// of this software and associated documentation files (the "Software"), to deal +//// in the Software without restriction, including without limitation the rights +//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//// copies of the Software, and to permit persons to whom the Software is +//// furnished to do so, subject to the following conditions: +//// +//// > The above copyright notice and this permission notice shall be included in all +//// copies or substantial portions of the Software. +//// +//// > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//// SOFTWARE. +//// +//// </details> +//// + +// Just in case we decide in the future to no longer include the above reference +// and license, this package was initially a port of the `elm-color-extra` module: +// +// https://github.com/noahzgordon/elm-color-extra +// + +// IMPORTS -------------------------------------------------------------------- + +import gleam/float +import gleam/list +import gleam_community/colour.{type Colour} + +// UTILITIES ------------------------------------------------------------------ + +fn intensity(colour_value: Float) -> Float { + // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef + case True { + _ if colour_value <=. 0.03928 -> colour_value /. 12.92 + _ -> { + // Is this guaranteed to be `OK`? + let assert Ok(i) = float.power({ colour_value +. 0.055 } /. 1.055, 2.4) + i + } + } +} + +// ACCESSIBILITY -------------------------------------------------------------- + +/// Returns the relative brightness of the given `Colour` as a `Float` between +/// 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// luminance(colour.white) // 1.0 +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn luminance(colour: Colour) -> Float { + // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef + let #(r, g, b, _) = colour.to_rgba(colour) + + let r_intensity = intensity(r) + let g_intensity = intensity(g) + let b_intensity = intensity(b) + + 0.2126 *. r_intensity +. 0.7152 *. g_intensity +. 0.0722 *. b_intensity +} + +/// Returns the contrast between two `Colour` values as a `Float` between 1.0, +/// and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// contrast_ratio(between: colour.white, and: colour.black) // 21.0 +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn contrast_ratio(between colour_a: Colour, and colour_b: Colour) -> Float { + // Calculation taken from https://www.w3.org/TR/WCAG20/#contrast-ratiodef + let luminance_a = luminance(colour_a) +. 0.05 + let luminance_b = luminance(colour_b) +. 0.05 + + case luminance_a >. luminance_b { + True -> luminance_a /. luminance_b + False -> luminance_b /. luminance_a + } +} + +/// Returns the `Colour` with the highest contrast between the base `Colour`, +/// and and the other provided `Colour` values. +/// +/// <details> +/// <summary>Example:</summary> +/// +/// ```gleam +/// fn example() { +/// maximum_contrast( +/// colour.yellow, +/// [colour.white, colour.dark_blue, colour.green], +/// ) +/// } +/// ``` +/// </details> +/// +/// <div style="position: relative;"> +/// <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues"> +/// <small>Spot a typo? Open an issue!</small> +/// </a> +/// <a style="position: absolute; right: 0;" href="#"> +/// <small>Back to top ↑</small> +/// </a> +/// </div> +/// +pub fn maximum_contrast( + base: Colour, + colours: List(Colour), +) -> Result(Colour, Nil) { + colours + |> list.sort(fn(colour_a, colour_b) { + let contrast_a = contrast_ratio(base, colour_a) + let contrast_b = contrast_ratio(base, colour_b) + + float.compare(contrast_b, contrast_a) + }) + |> list.first() +} diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl new file mode 100644 index 0000000..21e4c81 --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour.erl @@ -0,0 +1,511 @@ +-module(gleam_community@colour). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). + +-export([from_rgb255/3, from_rgb/3, from_rgba/4, from_hsla/4, from_hsl/3, from_rgb_hex/1, from_rgb_hex_string/1, from_rgba_hex/1, from_rgba_hex_string/1, to_rgba/1, to_hsla/1, to_css_rgba_string/1, to_rgba_hex/1, to_rgba_hex_string/1, to_rgb_hex/1, to_rgb_hex_string/1]). +-export_type([colour/0]). + +-opaque colour() :: {rgba, float(), float(), float(), float()} | + {hsla, float(), float(), float(), float()}. + +-spec valid_colour_value(float()) -> {ok, float()} | {error, nil}. +valid_colour_value(C) -> + case (C > 1.0) orelse (C < +0.0) of + true -> + {error, nil}; + + false -> + {ok, C} + end. + +-spec hue_to_rgb(float(), float(), float()) -> float(). +hue_to_rgb(Hue, M1, M2) -> + H = case Hue of + _ when Hue < +0.0 -> + Hue + 1.0; + + _ when Hue > 1.0 -> + Hue - 1.0; + + _ -> + Hue + end, + H_t_6 = H * 6.0, + H_t_2 = H * 2.0, + H_t_3 = H * 3.0, + case H of + _ when H_t_6 < 1.0 -> + M1 + (((M2 - M1) * H) * 6.0); + + _ when H_t_2 < 1.0 -> + M2; + + _ when H_t_3 < 2.0 -> + M1 + (((M2 - M1) * ((2.0 / 3.0) - H)) * 6.0); + + _ -> + M1 + end. + +-spec hex_string_to_int(binary()) -> {ok, integer()} | {error, nil}. +hex_string_to_int(Hex_string) -> + Hex = case Hex_string of + <<"#"/utf8, Hex_number/binary>> -> + Hex_number; + + <<"0x"/utf8, Hex_number@1/binary>> -> + Hex_number@1; + + _ -> + Hex_string + end, + _pipe = Hex, + _pipe@1 = gleam@string:lowercase(_pipe), + _pipe@2 = gleam@string:to_graphemes(_pipe@1), + _pipe@3 = gleam@list:reverse(_pipe@2), + gleam@list:index_fold( + _pipe@3, + {ok, 0}, + fun(Total, Char, Index) -> case Total of + {error, nil} -> + {error, nil}; + + {ok, V} -> + gleam@result:then(case Char of + <<"a"/utf8>> -> + {ok, 10}; + + <<"b"/utf8>> -> + {ok, 11}; + + <<"c"/utf8>> -> + {ok, 12}; + + <<"d"/utf8>> -> + {ok, 13}; + + <<"e"/utf8>> -> + {ok, 14}; + + <<"f"/utf8>> -> + {ok, 15}; + + _ -> + gleam@int:parse(Char) + end, fun(Num) -> + gleam@result:then( + gleam@int:power(16, gleam@int:to_float(Index)), + fun(Base) -> + {ok, + V + gleam@float:round( + gleam@int:to_float(Num) * Base + )} + end + ) + end) + end end + ). + +-spec hsla_to_rgba(float(), float(), float(), float()) -> {float(), + float(), + float(), + float()}. +hsla_to_rgba(H, S, L, A) -> + M2 = case L =< 0.5 of + true -> + L * (S + 1.0); + + false -> + (L + S) - (L * S) + end, + M1 = (L * 2.0) - M2, + R = hue_to_rgb(H + (1.0 / 3.0), M1, M2), + G = hue_to_rgb(H, M1, M2), + B = hue_to_rgb(H - (1.0 / 3.0), M1, M2), + {R, G, B, A}. + +-spec rgba_to_hsla(float(), float(), float(), float()) -> {float(), + float(), + float(), + float()}. +rgba_to_hsla(R, G, B, A) -> + Min_colour = gleam@float:min(R, gleam@float:min(G, B)), + Max_colour = gleam@float:max(R, gleam@float:max(G, B)), + H1 = case true of + _ when Max_colour =:= R -> + gleam@float:divide(G - B, Max_colour - Min_colour); + + _ when Max_colour =:= G -> + _pipe = gleam@float:divide(B - R, Max_colour - Min_colour), + gleam@result:then(_pipe, fun(D) -> {ok, 2.0 + D} end); + + _ -> + _pipe@1 = gleam@float:divide(R - G, Max_colour - Min_colour), + gleam@result:then(_pipe@1, fun(D@1) -> {ok, 4.0 + D@1} end) + end, + H2 = case H1 of + {ok, V} -> + {ok, V * (1.0 / 6.0)}; + + _ -> + H1 + end, + H3 = case H2 of + {ok, V@1} when V@1 < +0.0 -> + V@1 + 1.0; + + {ok, V@2} -> + V@2; + + _ -> + +0.0 + end, + L = (Min_colour + Max_colour) / 2.0, + S = case true of + _ when Min_colour =:= Max_colour -> + +0.0; + + _ when L < 0.5 -> + case (Max_colour + Min_colour) of + 0.0 -> 0.0; + Gleam@denominator -> (Max_colour - Min_colour) / Gleam@denominator + end; + + _ -> + case ((2.0 - Max_colour) - Min_colour) of + 0.0 -> 0.0; + Gleam@denominator@1 -> (Max_colour - Min_colour) / Gleam@denominator@1 + end + end, + {H3, S, L, A}. + +-spec from_rgb255(integer(), integer(), integer()) -> {ok, colour()} | + {error, nil}. +from_rgb255(Red, Green, Blue) -> + gleam@result:then( + begin + _pipe = Red, + _pipe@1 = gleam@int:to_float(_pipe), + _pipe@2 = gleam@float:divide(_pipe@1, 255.0), + gleam@result:then(_pipe@2, fun valid_colour_value/1) + end, + fun(R) -> + gleam@result:then( + begin + _pipe@3 = Green, + _pipe@4 = gleam@int:to_float(_pipe@3), + _pipe@5 = gleam@float:divide(_pipe@4, 255.0), + gleam@result:then(_pipe@5, fun valid_colour_value/1) + end, + fun(G) -> + gleam@result:then( + begin + _pipe@6 = Blue, + _pipe@7 = gleam@int:to_float(_pipe@6), + _pipe@8 = gleam@float:divide(_pipe@7, 255.0), + gleam@result:then(_pipe@8, fun valid_colour_value/1) + end, + fun(B) -> {ok, {rgba, R, G, B, 1.0}} end + ) + end + ) + end + ). + +-spec from_rgb(float(), float(), float()) -> {ok, colour()} | {error, nil}. +from_rgb(Red, Green, Blue) -> + gleam@result:then( + valid_colour_value(Red), + fun(R) -> + gleam@result:then( + valid_colour_value(Green), + fun(G) -> + gleam@result:then( + valid_colour_value(Blue), + fun(B) -> {ok, {rgba, R, G, B, 1.0}} end + ) + end + ) + end + ). + +-spec from_rgba(float(), float(), float(), float()) -> {ok, colour()} | + {error, nil}. +from_rgba(Red, Green, Blue, Alpha) -> + gleam@result:then( + valid_colour_value(Red), + fun(R) -> + gleam@result:then( + valid_colour_value(Green), + fun(G) -> + gleam@result:then( + valid_colour_value(Blue), + fun(B) -> + gleam@result:then( + valid_colour_value(Alpha), + fun(A) -> {ok, {rgba, R, G, B, A}} end + ) + end + ) + end + ) + end + ). + +-spec from_hsla(float(), float(), float(), float()) -> {ok, colour()} | + {error, nil}. +from_hsla(Hue, Saturation, Lightness, Alpha) -> + gleam@result:then( + valid_colour_value(Hue), + fun(H) -> + gleam@result:then( + valid_colour_value(Saturation), + fun(S) -> + gleam@result:then( + valid_colour_value(Lightness), + fun(L) -> + gleam@result:then( + valid_colour_value(Alpha), + fun(A) -> {ok, {hsla, H, S, L, A}} end + ) + end + ) + end + ) + end + ). + +-spec from_hsl(float(), float(), float()) -> {ok, colour()} | {error, nil}. +from_hsl(Hue, Saturation, Lightness) -> + from_hsla(Hue, Saturation, Lightness, 1.0). + +-spec from_rgb_hex(integer()) -> {ok, colour()} | {error, nil}. +from_rgb_hex(Hex) -> + case (Hex > 16#ffffff) orelse (Hex < 0) of + true -> + {error, nil}; + + false -> + R = begin + _pipe = erlang:'bsr'(Hex, 16), + erlang:'band'(_pipe, 16#ff) + end, + G = begin + _pipe@1 = erlang:'bsr'(Hex, 8), + erlang:'band'(_pipe@1, 16#ff) + end, + B = erlang:'band'(Hex, 16#ff), + from_rgb255(R, G, B) + end. + +-spec from_rgb_hex_string(binary()) -> {ok, colour()} | {error, nil}. +from_rgb_hex_string(Hex_string) -> + gleam@result:then( + hex_string_to_int(Hex_string), + fun(Hex_int) -> from_rgb_hex(Hex_int) end + ). + +-spec from_rgba_hex(integer()) -> {ok, colour()} | {error, nil}. +from_rgba_hex(Hex) -> + case (Hex > 16#ffffffff) orelse (Hex < 0) of + true -> + {error, nil}; + + false -> + _assert_subject = begin + _pipe = erlang:'bsr'(Hex, 24), + _pipe@1 = erlang:'band'(_pipe, 16#ff), + _pipe@2 = gleam@int:to_float(_pipe@1), + gleam@float:divide(_pipe@2, 255.0) + end, + {ok, R} = case _assert_subject of + {ok, _} -> _assert_subject; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail, + module => <<"gleam_community/colour"/utf8>>, + function => <<"from_rgba_hex"/utf8>>, + line => 588}) + end, + _assert_subject@1 = begin + _pipe@3 = erlang:'bsr'(Hex, 16), + _pipe@4 = erlang:'band'(_pipe@3, 16#ff), + _pipe@5 = gleam@int:to_float(_pipe@4), + gleam@float:divide(_pipe@5, 255.0) + end, + {ok, G} = case _assert_subject@1 of + {ok, _} -> _assert_subject@1; + _assert_fail@1 -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail@1, + module => <<"gleam_community/colour"/utf8>>, + function => <<"from_rgba_hex"/utf8>>, + line => 594}) + end, + _assert_subject@2 = begin + _pipe@6 = erlang:'bsr'(Hex, 8), + _pipe@7 = erlang:'band'(_pipe@6, 16#ff), + _pipe@8 = gleam@int:to_float(_pipe@7), + gleam@float:divide(_pipe@8, 255.0) + end, + {ok, B} = case _assert_subject@2 of + {ok, _} -> _assert_subject@2; + _assert_fail@2 -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail@2, + module => <<"gleam_community/colour"/utf8>>, + function => <<"from_rgba_hex"/utf8>>, + line => 600}) + end, + _assert_subject@3 = begin + _pipe@9 = erlang:'band'(Hex, 16#ff), + _pipe@10 = gleam@int:to_float(_pipe@9), + gleam@float:divide(_pipe@10, 255.0) + end, + {ok, A} = case _assert_subject@3 of + {ok, _} -> _assert_subject@3; + _assert_fail@3 -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail@3, + module => <<"gleam_community/colour"/utf8>>, + function => <<"from_rgba_hex"/utf8>>, + line => 606}) + end, + from_rgba(R, G, B, A) + end. + +-spec from_rgba_hex_string(binary()) -> {ok, colour()} | {error, nil}. +from_rgba_hex_string(Hex_string) -> + gleam@result:then( + hex_string_to_int(Hex_string), + fun(Hex_int) -> from_rgba_hex(Hex_int) end + ). + +-spec to_rgba(colour()) -> {float(), float(), float(), float()}. +to_rgba(Colour) -> + case Colour of + {rgba, R, G, B, A} -> + {R, G, B, A}; + + {hsla, H, S, L, A@1} -> + hsla_to_rgba(H, S, L, A@1) + end. + +-spec to_hsla(colour()) -> {float(), float(), float(), float()}. +to_hsla(Colour) -> + case Colour of + {hsla, H, S, L, A} -> + {H, S, L, A}; + + {rgba, R, G, B, A@1} -> + rgba_to_hsla(R, G, B, A@1) + end. + +-spec to_css_rgba_string(colour()) -> binary(). +to_css_rgba_string(Colour) -> + {R, G, B, A} = to_rgba(Colour), + Percent = fun(X) -> + _assert_subject = begin + _pipe = X, + _pipe@1 = gleam@float:multiply(_pipe, 10000.0), + _pipe@2 = gleam@float:round(_pipe@1), + _pipe@3 = gleam@int:to_float(_pipe@2), + gleam@float:divide(_pipe@3, 100.0) + end, + {ok, P} = case _assert_subject of + {ok, _} -> _assert_subject; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail, + module => <<"gleam_community/colour"/utf8>>, + function => <<"to_css_rgba_string"/utf8>>, + line => 704}) + end, + P + end, + Round_to = fun(X@1) -> + _assert_subject@1 = begin + _pipe@4 = X@1, + _pipe@5 = gleam@float:multiply(_pipe@4, 1000.0), + _pipe@6 = gleam@float:round(_pipe@5), + _pipe@7 = gleam@int:to_float(_pipe@6), + gleam@float:divide(_pipe@7, 1000.0) + end, + {ok, R@1} = case _assert_subject@1 of + {ok, _} -> _assert_subject@1; + _assert_fail@1 -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail@1, + module => <<"gleam_community/colour"/utf8>>, + function => <<"to_css_rgba_string"/utf8>>, + line => 716}) + end, + R@1 + end, + gleam@string:join( + [<<"rgba("/utf8>>, + <<(gleam@float:to_string(Percent(R)))/binary, "%,"/utf8>>, + <<(gleam@float:to_string(Percent(G)))/binary, "%,"/utf8>>, + <<(gleam@float:to_string(Percent(B)))/binary, "%,"/utf8>>, + gleam@float:to_string(Round_to(A)), + <<")"/utf8>>], + <<""/utf8>> + ). + +-spec to_rgba_hex(colour()) -> integer(). +to_rgba_hex(Colour) -> + {R, G, B, A} = to_rgba(Colour), + Red = begin + _pipe = R * 255.0, + _pipe@1 = gleam@float:round(_pipe), + erlang:'bsl'(_pipe@1, 24) + end, + Green = begin + _pipe@2 = G * 255.0, + _pipe@3 = gleam@float:round(_pipe@2), + erlang:'bsl'(_pipe@3, 16) + end, + Blue = begin + _pipe@4 = B * 255.0, + _pipe@5 = gleam@float:round(_pipe@4), + erlang:'bsl'(_pipe@5, 8) + end, + Alpha = begin + _pipe@6 = A * 255.0, + gleam@float:round(_pipe@6) + end, + ((Red + Green) + Blue) + Alpha. + +-spec to_rgba_hex_string(colour()) -> binary(). +to_rgba_hex_string(Colour) -> + _pipe = to_rgba_hex(Colour), + gleam@int:to_base16(_pipe). + +-spec to_rgb_hex(colour()) -> integer(). +to_rgb_hex(Colour) -> + {R, G, B, _} = to_rgba(Colour), + Red = begin + _pipe = R * 255.0, + _pipe@1 = gleam@float:round(_pipe), + erlang:'bsl'(_pipe@1, 16) + end, + Green = begin + _pipe@2 = G * 255.0, + _pipe@3 = gleam@float:round(_pipe@2), + erlang:'bsl'(_pipe@3, 8) + end, + Blue = begin + _pipe@4 = B * 255.0, + gleam@float:round(_pipe@4) + end, + (Red + Green) + Blue. + +-spec to_rgb_hex_string(colour()) -> binary(). +to_rgb_hex_string(Colour) -> + _pipe = to_rgb_hex(Colour), + gleam@int:to_base16(_pipe). diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl new file mode 100644 index 0000000..64d37bf --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl @@ -0,0 +1,73 @@ +-module(gleam_community@colour@accessibility). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). + +-export([luminance/1, contrast_ratio/2, maximum_contrast/2]). + +-spec intensity(float()) -> float(). +intensity(Colour_value) -> + case true of + _ when Colour_value =< 0.03928 -> + Colour_value / 12.92; + + _ -> + _assert_subject = gleam@float:power( + (Colour_value + 0.055) / 1.055, + 2.4 + ), + {ok, I} = case _assert_subject of + {ok, _} -> _assert_subject; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Assertion pattern match failed"/utf8>>, + value => _assert_fail, + module => <<"gleam_community/colour/accessibility"/utf8>>, + function => <<"intensity"/utf8>>, + line => 62}) + end, + I + end. + +-spec luminance(gleam_community@colour:colour()) -> float(). +luminance(Colour) -> + {R, G, B, _} = gleam_community@colour:to_rgba(Colour), + R_intensity = intensity(R), + G_intensity = intensity(G), + B_intensity = intensity(B), + ((0.2126 * R_intensity) + (0.7152 * G_intensity)) + (0.0722 * B_intensity). + +-spec contrast_ratio( + gleam_community@colour:colour(), + gleam_community@colour:colour() +) -> float(). +contrast_ratio(Colour_a, Colour_b) -> + Luminance_a = luminance(Colour_a) + 0.05, + Luminance_b = luminance(Colour_b) + 0.05, + case Luminance_a > Luminance_b of + true -> + case Luminance_b of + 0.0 -> 0.0; + Gleam@denominator -> Luminance_a / Gleam@denominator + end; + + false -> + case Luminance_a of + 0.0 -> 0.0; + Gleam@denominator@1 -> Luminance_b / Gleam@denominator@1 + end + end. + +-spec maximum_contrast( + gleam_community@colour:colour(), + list(gleam_community@colour:colour()) +) -> {ok, gleam_community@colour:colour()} | {error, nil}. +maximum_contrast(Base, Colours) -> + _pipe = Colours, + _pipe@1 = gleam@list:sort( + _pipe, + fun(Colour_a, Colour_b) -> + Contrast_a = contrast_ratio(Base, Colour_a), + Contrast_b = contrast_ratio(Base, Colour_b), + gleam@float:compare(Contrast_b, Contrast_a) + end + ), + gleam@list:first(_pipe@1). diff --git a/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src new file mode 100644 index 0000000..a327650 --- /dev/null +++ b/aoc2023/build/packages/gleam_community_colour/src/gleam_community_colour.app.src @@ -0,0 +1,9 @@ +{application, gleam_community_colour, [ + {vsn, "1.2.0"}, + {applications, [gleam_stdlib, + gleeunit]}, + {description, "Colour types, conversions, and other utilities"}, + {modules, [gleam_community@colour, + gleam_community@colour@accessibility]}, + {registered, []} +]}. |