glimmer-dsl-web-icons 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3c1ec4d7a84f74fc29a957d09695b31aded05539f4961c66e682e644726c921c
4
+ data.tar.gz: 37defa08db233e497232f04935599063885d0730a58d39f67284905b4ad6c21c
5
+ SHA512:
6
+ metadata.gz: 67d3ad8b95772f514e9bbe02a8c16c13b42e58f275febb5540d46258e247571b9196368a21ce4ccea1437a5c6771781491a66ccb270c345810cf571e4f3d790b
7
+ data.tar.gz: be618afd010463c11818defed8000de4d45a50c6a14b87f9dd748e0f9ce6ea724a2ec32ba336c46739f20f9115b8cda4606e3e0b477e528310777ba8926da673
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Allan Ientz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # glimmer-dsl-web-icons
2
+
3
+ Icon library support for [glimmer-dsl-web](https://github.com/AndyObtiva/glimmer-dsl-web)
4
+ projects. Ships [Lucide](https://lucide.dev), [Heroicons](https://heroicons.com),
5
+ and [Phosphor](https://phosphoricons.com) today.
6
+
7
+ ## Why
8
+
9
+ glimmer-dsl-web has no built-in icon story: every project doing real UI work
10
+ ends up hand-copying SVG path data into its own components. This gem fills
11
+ that gap by shipping icon data from popular icon libraries in
12
+ glimmer-dsl-web's own native format -- so an icon becomes a normal DSL call
13
+ instead of a pile of hand-maintained SVG markup.
14
+
15
+ ## Status
16
+
17
+ Early. Three libraries ship today, deliberately chosen (after Lucide) to
18
+ stress-test the design against real differences rather than guessed ones:
19
+
20
+ - `:lucide` -- one style, stroke-based.
21
+ - `:heroicons_outline`, `:heroicons_solid`, `:heroicons_mini`,
22
+ `:heroicons_micro` -- Heroicons' own four style/size variants (24px
23
+ stroke, 24px fill, 20px fill, 16px fill). Each is a real, separately
24
+ designed icon set, not a resize.
25
+ - `:phosphor_thin`, `:phosphor_light`, `:phosphor_regular`, `:phosphor_bold`,
26
+ `:phosphor_fill`, `:phosphor_duotone` -- Phosphor's six "weights". Unlike
27
+ Heroicons, all six share one identical root `<svg>` (fill-based, same
28
+ viewBox) -- still verified per weight rather than assumed, since nothing
29
+ guarantees a future release keeps it that way, but it turned out not to
30
+ be where Phosphor's real difference is.
31
+
32
+ Each of these was added for a specific reason, not just to pad the list:
33
+
34
+ - **Heroicons** showed the root `<svg>` attributes (fill/stroke/viewBox)
35
+ aren't universal -- an earlier version hardcoded Lucide's stroke-based
36
+ convention directly into the `Icon` component, and Heroicons' solid
37
+ styles (`fill: currentColor`, no stroke at all) broke that assumption.
38
+ Fixed by moving those attrs into the registry, per library --
39
+ `register(library, icons, attrs: {...})` -- see `registry.rb`.
40
+ - **Phosphor** was chosen specifically to test *multi-color* icon support,
41
+ flagged from the start as an unvalidated gap (single-color libraries
42
+ don't exercise it). Its `duotone` weight turned out to need **no design
43
+ change at all**: the two-tone effect is just two `<path>`s sharing one
44
+ `fill: currentColor`, where the background layer carries its own
45
+ `opacity="0.2"` -- a per-*shape* attribute, which this gem's
46
+ `[[tag, attrs], ...]` format already carried through generically from
47
+ day one (the same mechanism that already handled Heroicons' per-path
48
+ `stroke-linecap`). Confirmed against all 1512 duotone icons, not
49
+ assumed from one example -- see `generate/phosphor.rb`.
50
+
51
+ The public API (`library:` option, one data file per library that
52
+ self-registers with the registry, `attrs:` for whatever a library's icons
53
+ share at the root) has now absorbed two real design pressures without
54
+ breaking callers of the first library added under it.
55
+
56
+ ## Roadmap: planned libraries
57
+
58
+ Next additions are meant to match the icon-library coverage of
59
+ [`rails_icons`](https://github.com/Rails-Designer/rails_icons) /
60
+ [`Rails-Designer/icons`](https://github.com/Rails-Designer/icons) -- the
61
+ prior art this gem's two-layer shape (data registry + thin rendering
62
+ component) is deliberately modeled on. `rails_icons` supports 12 libraries
63
+ total; the full list, with the 3 already shipped checked off:
64
+
65
+ - [x] [Lucide](https://lucide.dev) (1,799 icons)
66
+ - [x] [Heroicons](https://heroicons.com) (4 variants, 324/324/324/316 icons)
67
+ - [x] [Phosphor](https://phosphoricons.com) (6 weights, 1,512 icons each)
68
+ - [ ] [Tabler](https://tabler.io/icons) (~5,700 icons)
69
+ - [ ] [Hugeicons](https://hugeicons.com) (~4,600 icons)
70
+ - [ ] [Boxicons](https://boxicons.com) (~1,600 icons)
71
+ - [ ] [Radix Icons](https://www.radix-ui.com/icons) (~300 icons)
72
+ - [ ] [Feather](https://feathericons.com) (~280 icons)
73
+ - [ ] [Linear Icons](https://linear.app) (~170 icons)
74
+ - [ ] Flags (~540 icons)
75
+ - [ ] Weather icons (~215 icons)
76
+ - [ ] SidekickIcons (~49 icons, complements Heroicons)
77
+
78
+ Not committed to this exact order, and not committed to shipping all nine
79
+ remaining -- each one only earns a slot once it's actually confirmed against its real
80
+ source (the way Lucide/Heroicons/Phosphor were), and only kept if it either
81
+ works with the current design as-is or teaches it something new, the same
82
+ bar Heroicons and Phosphor were held to above. Tabler and Feather are
83
+ stroke-based like Lucide and are expected to need no design changes; Flags
84
+ and Weather are the more likely candidates to surface something new (Flags
85
+ in particular may not be simple monochrome shapes).
86
+
87
+ ## Installing in a Rails app
88
+
89
+ This assumes your app already has glimmer-dsl-web's Opal build pipeline set
90
+ up (i.e. you followed glimmer-dsl-web's own
91
+ [Rails setup guide](https://github.com/AndyObtiva/glimmer-dsl-web/blob/master/docs/setup/rails_7_8_build_pipeline.md)
92
+ and have a working `config/initializers/opal.rb`).
93
+
94
+ 1. Add to your `Gemfile` and `bundle install`:
95
+
96
+ ```ruby
97
+ gem 'glimmer-dsl-web-icons'
98
+ ```
99
+
100
+ 2. **Add it to `config.opal.use_gems` in `config/initializers/opal.rb`.**
101
+ This step is easy to miss and the gem will silently fail to compile into
102
+ your browser bundle without it:
103
+
104
+ ```ruby
105
+ config.opal.use_gems = %w[glimmer-dsl-web glimmer-dsl-web-icons]
106
+ ```
107
+
108
+ Why: Opal compiles your `app/assets/opal` code to JavaScript *ahead of
109
+ time*, so there's no Ruby process in the browser to resolve a `require`
110
+ later the way a normal Rails `Gemfile` gem would be. `use_gems` is the
111
+ explicit whitelist that tells the Opal build step which gems' Ruby
112
+ source to scan and compile into that bundle. Being in your `Gemfile` only
113
+ makes a gem available to server-side Ruby -- any gem your Opal-side code
114
+ `require`s has to *also* be listed here, and glimmer-dsl-web's own setup
115
+ guide only shows this line with itself in the array, so it's worth
116
+ calling out explicitly rather than leaving people to hit the failure and
117
+ guess.
118
+
119
+ 3. In whichever Opal file needs icons, require this gem plus the library
120
+ data file(s) you want (each library is opt-in, so nothing loads that you
121
+ don't ask for):
122
+
123
+ ```ruby
124
+ require 'glimmer-dsl-web-icons'
125
+ require 'glimmer/dsl/web/icons/lucide'
126
+ require 'glimmer/dsl/web/icons/heroicons' # if you want Heroicons too
127
+ require 'glimmer/dsl/web/icons/phosphor' # if you want Phosphor too
128
+ ```
129
+
130
+ Note: each data file above compiles its *entire* icon set into your
131
+ Opal bundle once required -- Lucide alone is ~1800 icons, Phosphor's
132
+ six weights ~9000 between them. There's no way yet to require only the
133
+ handful of icons you actually use (that would mean generating one file
134
+ per icon instead of one per library) -- a real tradeoff, tracked as a
135
+ possible future change rather than solved here.
136
+
137
+ ## Usage
138
+
139
+ Every icon, from any library, is rendered by the same `icon` call --
140
+ there's no per-library Ruby API, only different `library:` values (and
141
+ different icon names within each):
142
+
143
+ ```ruby
144
+ icon(name, library: :lucide, size: 24)
145
+ ```
146
+
147
+ | Option | Required | Default | Meaning |
148
+ | --- | --- | --- | --- |
149
+ | `name` | yes | -- | Icon name string, e.g. `'circle-check'`. Can be passed positionally (`icon('circle-check', ...)`, mirroring shadcn_glimmer's `ShButton`/`ShIcon` convention) or as `name:` -- both are equivalent. |
150
+ | `library` | no | `:lucide` | Which registered library/variant to look the name up in (see per-library tables below). Its data file must be `require`d first (Installing, step 3), or `Icons.lookup` raises `UnknownLibraryError`. |
151
+ | `size` | no | `24` | Sets both `width` and `height` on the root `<svg>`, in pixels. The only option that works identically across every library. |
152
+
153
+ An unrecognized icon name raises `Icons::UnknownIconError` rather than
154
+ rendering nothing, so a typo fails loudly instead of silently.
155
+
156
+ Root `<svg>` attributes (fill/stroke/stroke-width/viewBox) are fixed **per
157
+ library/variant**, not configurable per call -- they come entirely from
158
+ whichever `library:` value you pick. There's no `attrs:`/`stroke_width:`
159
+ override at the call site today; if you need a different stroke width than
160
+ a library's default, that's a gap, not a hidden option.
161
+
162
+ ### Lucide -- `:lucide` (default)
163
+
164
+ 1,799 icons, one style, stroke-based.
165
+
166
+ ```ruby
167
+ icon('circle-check', library: :lucide, size: 20)
168
+ icon('circle-check', size: 20) # library: :lucide is the default, can be omitted
169
+ ```
170
+
171
+ Root `<svg>` attrs: `viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"`.
172
+
173
+ ### Heroicons -- `:heroicons_outline`, `:heroicons_solid`, `:heroicons_mini`, `:heroicons_micro`
174
+
175
+ 4 independently-designed style/size variants. The variant *is* the
176
+ `library:` value -- there's no separate `style:`/`variant:` option. 324
177
+ icons per variant (316 for `micro` -- Heroicons ships a few fewer icons at
178
+ that size).
179
+
180
+ ```ruby
181
+ icon('heart', library: :heroicons_outline) # 24px, stroke-based
182
+ icon('heart', library: :heroicons_solid) # 24px, fill-based
183
+ icon('heart', library: :heroicons_mini) # 20px, fill-based
184
+ icon('heart', library: :heroicons_micro) # 16px, fill-based
185
+ ```
186
+
187
+ | `library:` | viewBox | fill | stroke |
188
+ | --- | --- | --- | --- |
189
+ | `:heroicons_outline` | `0 0 24 24` | `none` | `currentColor`, `stroke-width: 1.5` |
190
+ | `:heroicons_solid` | `0 0 24 24` | `currentColor` | none |
191
+ | `:heroicons_mini` | `0 0 20 20` | `currentColor` | none |
192
+ | `:heroicons_micro` | `0 0 16 16` | `currentColor` | none |
193
+
194
+ ### Phosphor -- `:phosphor_thin`, `:phosphor_light`, `:phosphor_regular`, `:phosphor_bold`, `:phosphor_fill`, `:phosphor_duotone`
195
+
196
+ 6 weights, selected via `library:` the same way as Heroicons' variants.
197
+ 1,512 icons per weight.
198
+
199
+ ```ruby
200
+ icon('heart', library: :phosphor_thin)
201
+ icon('heart', library: :phosphor_light)
202
+ icon('heart', library: :phosphor_regular)
203
+ icon('heart', library: :phosphor_bold)
204
+ icon('heart', library: :phosphor_fill) # flat solid
205
+ icon('heart', library: :phosphor_duotone) # two-tone: light bg shape + solid fg shape
206
+ ```
207
+
208
+ All six weights share identical root `<svg>` attrs: `viewBox="0 0 256 256" fill="currentColor"`.
209
+ The thin/light/regular/bold difference is baked into each icon's own path
210
+ data (there's no adjustable `stroke-width` the way Lucide has one), and
211
+ `duotone`'s two-tone look comes from two overlapping shapes at different
212
+ opacities within the icon data itself -- nothing you pass at the call site
213
+ changes it.
214
+
215
+ ## Development
216
+
217
+ No Bundler required to hack on this gem -- it's pure Ruby with only
218
+ `rake`/`minitest` as dev dependencies (both ship with a standard Ruby
219
+ install). Run the test suite with:
220
+
221
+ ```
222
+ rake test
223
+ ```
224
+
225
+ `generate/lucide.rb`, `generate/heroicons.rb`, and `generate/phosphor.rb`
226
+ are dev-only scripts (not shipped in the gem) that regenerate their
227
+ respective `lib/glimmer/dsl/web/icons/*.rb` files from a local
228
+ `npm install lucide` / `npm install heroicons` /
229
+ `npm install @phosphor-icons/core` checkout under `references/` -- see
230
+ each script's header comment for how to re-sync when a library releases
231
+ new icons.
232
+
233
+ ## Adding another library
234
+
235
+ Each library is one file under `lib/glimmer/dsl/web/icons/` that builds an
236
+ `{"icon-name" => [[tag, attrs], ...]}` Hash and calls
237
+ `Glimmer::DSL::Web::Icons.register(:your_library, that_hash, attrs: {...})`,
238
+ where `attrs:` is whatever root `<svg>` attributes every icon in that
239
+ library shares (see `registry.rb`). Whether a new library needs one
240
+ registration or several (the way Heroicons and Phosphor both needed
241
+ several) depends on whether it actually ships multiple
242
+ independently-designed styles -- confirm that against the library's real
243
+ source rather than assuming either way, the same way each of these three
244
+ was. See "Roadmap" above for the specific libraries planned next.
245
+
246
+ ## License
247
+
248
+ MIT.