its-swiss 0.7.0 → 0.7.2
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 +4 -4
- data/CHANGELOG.md +23 -2
- data/README.md +16 -7
- data/app/assets/stylesheets/its_swiss/components.css +18 -7
- data/app/assets/stylesheets/its_swiss/type.css +3 -2
- data/app/helpers/its_swiss/application_helper.rb +18 -8
- data/lib/its_swiss/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f884ebf4471bd9c1bdc232a35cf327949466b3db98748a6bb008f985314e091
|
|
4
|
+
data.tar.gz: d8a1e3b75d21f52e96850a57adf3dcbc72242638f9f7d62fe71126bf8ffa5272
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5157d8c0cd8ad7db0db4025199d76ce4888ed2ad85d4ffb69a4427c97539482f646f56fe1fb274c831cf9f4d4a99a02185e9eb230cbc6516294bb805f631f815
|
|
7
|
+
data.tar.gz: 7a2ca8413c7cfdaa998a033bdeb9cae176cf7487cdab8af8162b784d01006f264c835a092a11f48bff1c549459dd61166259b6ca9f73771cd3241d0bbfc1430c
|
data/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
Semver. Consumers pin `~> 0.1`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 0.7.2 — 2026-09-04
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **A control's text sits on its rule.** 0.7.1 took the text off the faces
|
|
10
|
+
and left it on the first of the control's two lines, a whole line above
|
|
11
|
+
the rule. It is set on the second line now, the one the rule closes, so
|
|
12
|
+
the type stands on its rule; the first line is air under the label. The
|
|
13
|
+
box is still two lines and still on the grid.
|
|
14
|
+
|
|
15
|
+
## 0.7.1 — 2026-09-04
|
|
6
16
|
|
|
7
17
|
### Fixed
|
|
8
18
|
|
|
19
|
+
- **A control's text was clipped at the rule.** The faces put every
|
|
20
|
+
baseline on the under edge of its line by giving the type no descent, and
|
|
21
|
+
a browser centres an input's text in a box of its own and clips it there
|
|
22
|
+
— so with `font: inherit` every descender in a field, a select or a
|
|
23
|
+
textarea was cut off. A control's text is now set in `--font-family`
|
|
24
|
+
itself, with the font's own metrics, on one line inside the two-line box:
|
|
25
|
+
the box stays on the grid and the type is deliberately off the baseline,
|
|
26
|
+
the way a button's label is. `its_swiss_typeface` takes `family:` and
|
|
27
|
+
declares the typeface under its own name as well, so that `--font-family`
|
|
28
|
+
resolves to it.
|
|
29
|
+
|
|
9
30
|
- **A pinned specimen stopped existing.** Pages replaces the whole site on
|
|
10
31
|
every deploy, so a version-stamped page survives only if the run writes it
|
|
11
32
|
again. The step meant to carry them forward read them back off the live
|
|
@@ -20,7 +41,7 @@ Semver. Consumers pin `~> 0.1`.
|
|
|
20
41
|
from itself. `0.6.0.html` is restored there, rendered from the 0.6.0 commit
|
|
21
42
|
by that version's own `bin/specimen`.
|
|
22
43
|
|
|
23
|
-
## 0.7.0 —
|
|
44
|
+
## 0.7.0 — 2026-09-04
|
|
24
45
|
|
|
25
46
|
Every baseline on the grid, in every browser, whatever the font.
|
|
26
47
|
|
data/README.md
CHANGED
|
@@ -171,17 +171,25 @@ be corrected twice. Plain text dropped straight into a `<footer>` or a `<div>`
|
|
|
171
171
|
is in step and, in Safari, off the baseline; put it in a paragraph. The shell
|
|
172
172
|
does, for the `:footer` slot.
|
|
173
173
|
|
|
174
|
-
A control is two lines:
|
|
175
|
-
|
|
174
|
+
A control is two lines: a line of air under the label, then the line the
|
|
175
|
+
type is set on, which the rule closes, with the rule's width taken out of the
|
|
176
|
+
first — so the type stands on its rule the way a line of handwriting stands
|
|
177
|
+
on a ruled page. A button is a box, two lines tall with
|
|
176
178
|
its label centred in it, and its label's baseline is the one baseline in the
|
|
177
179
|
library that is not on a line — on purpose, since a label set on the second
|
|
178
180
|
line of a two-line box reads as a field with a rule under it. Its keyline is
|
|
179
181
|
an inset shadow rather than a border, so the box is the label's line and two
|
|
180
|
-
paddings and nothing else.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
paddings and nothing else.
|
|
183
|
+
|
|
184
|
+
A control's own text — an input, a select, a textarea — is the other run of
|
|
185
|
+
type the library takes off the baseline, and it does so on purpose too. A
|
|
186
|
+
browser sets that text in a box of its own, centres it there and clips it
|
|
187
|
+
there, and on a face with no descent every descender was cut off at the
|
|
188
|
+
rule. So the text is set in `--font-family` itself, with the font's own
|
|
189
|
+
metrics, on the line the rule closes: the box is on the grid, the line is
|
|
190
|
+
the ladder's, and where the baseline falls inside the line is the font's. Which means the typeface has to exist under its own name as well as
|
|
191
|
+
under the faces; `its_swiss_typeface` declares it there when given
|
|
192
|
+
`family:`, and `--font-family` names it.
|
|
185
193
|
|
|
186
194
|
#### Your own typeface
|
|
187
195
|
|
|
@@ -191,6 +199,7 @@ it:
|
|
|
191
199
|
```erb
|
|
192
200
|
<%= its_swiss_typeface regular: "inter-regular.woff2", bold: "inter-bold.woff2" %>
|
|
193
201
|
<%= its_swiss_typeface variable: "inter.woff2", mono: "jetbrains-mono.woff2" %>
|
|
202
|
+
<%= its_swiss_typeface variable: "inter.woff2", family: "Inter" %>
|
|
194
203
|
```
|
|
195
204
|
|
|
196
205
|
Put it after the library's stylesheets. The declarations are unlayered, and a
|
|
@@ -273,14 +273,25 @@
|
|
|
273
273
|
border-bottom: var(--rule-hair) solid var(--ink);
|
|
274
274
|
background: transparent;
|
|
275
275
|
color: inherit;
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
/* The one run of type in the library that is taken off the baseline on
|
|
277
|
+
purpose. A control's text is not in the document: the browser sets it
|
|
278
|
+
in a box of its own, centres it there and clips it there, and on a
|
|
279
|
+
face with no descent — the faces are what put every other baseline on
|
|
280
|
+
the under edge of its line — every descender was cut off at the rule.
|
|
281
|
+
So the type is set in the typeface itself, with the font's own
|
|
282
|
+
metrics, on one line. The line is the ladder's and so is the box; only
|
|
283
|
+
where the baseline falls inside the line is the font's. */
|
|
284
|
+
font-family: var(--font-family);
|
|
285
|
+
font-size: inherit;
|
|
286
|
+
font-weight: inherit;
|
|
287
|
+
line-height: var(--line);
|
|
288
|
+
/* A control is two lines of box, and the text sits on the second: the
|
|
289
|
+
line the rule closes, so the type stands on its rule the way a line of
|
|
290
|
+
handwriting stands on a ruled page, and the rule is on the grid. The
|
|
291
|
+
first line is air between the label and the text — the rule's width
|
|
292
|
+
comes out of it, so the box stays two lines exactly. */
|
|
279
293
|
block-size: var(--line-2);
|
|
280
|
-
|
|
281
|
-
under it. A control is two lines of box: one the text is set on, one
|
|
282
|
-
the rule closes. */
|
|
283
|
-
padding-block: 0 calc(var(--line) - var(--rule-hair));
|
|
294
|
+
padding-block: calc(var(--line) - var(--rule-hair)) 0;
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
.field textarea {
|
|
@@ -202,8 +202,9 @@
|
|
|
202
202
|
trimmed through its first and last child and would be corrected twice.
|
|
203
203
|
A list item or a definition holds either, so they are trimmed only when
|
|
204
204
|
they hold text. A control's own text — an input, a select, a textarea —
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
is not trimmed and not on a face: components.css sets it in the typeface
|
|
206
|
+
itself, on one line, because a browser centres it in a box of its own
|
|
207
|
+
and clips it there.
|
|
207
208
|
|
|
208
209
|
The correction is written for the browser that uses it. WebKit trims a
|
|
209
210
|
line to its cap height rounded to a whole pixel while its cap unit is
|
|
@@ -40,21 +40,29 @@ module ItsSwiss
|
|
|
40
40
|
#
|
|
41
41
|
# <%= its_swiss_typeface regular: "inter-regular.woff2", bold: "inter-bold.woff2" %>
|
|
42
42
|
# <%= its_swiss_typeface variable: "inter.woff2", mono: "jetbrains-mono.woff2" %>
|
|
43
|
+
# <%= its_swiss_typeface variable: "inter.woff2", family: "Inter" %>
|
|
44
|
+
#
|
|
45
|
+
# family: declares the same files under the font's own name as well, with
|
|
46
|
+
# the font's own metrics. A control's text is set in --font-family rather
|
|
47
|
+
# than on a face, so an application that names its typeface there needs
|
|
48
|
+
# the name to resolve — or its fields are set in the machine's grotesque
|
|
49
|
+
# while the page around them is set in its own.
|
|
43
50
|
#
|
|
44
51
|
# Unlayered, which is how it wins: a name defined outside a layer beats
|
|
45
52
|
# the same name defined inside one, the way the application's rules beat
|
|
46
53
|
# the library's. Put it after the library's stylesheets all the same, for
|
|
47
54
|
# a browser that resolves a name by order rather than by layer.
|
|
48
|
-
def its_swiss_typeface(regular: nil, bold: nil, variable: nil, mono: nil)
|
|
55
|
+
def its_swiss_typeface(regular: nil, bold: nil, variable: nil, mono: nil, family: nil)
|
|
49
56
|
raise ArgumentError, "a regular file or a variable one" unless regular || variable
|
|
50
57
|
raise ArgumentError, "a variable file carries both weights" if variable && (regular || bold)
|
|
51
58
|
|
|
52
59
|
weights = variable ? { "100 900" => variable } : { "400" => regular, "700" => bold }.compact
|
|
53
60
|
|
|
54
|
-
faces = ItsSwiss::FACES.flat_map do |
|
|
55
|
-
weights.map { |weight, file| its_swiss_face(
|
|
61
|
+
faces = ItsSwiss::FACES.flat_map do |family_name, ratio|
|
|
62
|
+
weights.map { |weight, file| its_swiss_face(family_name, file, ratio, weight: weight) }
|
|
56
63
|
end
|
|
57
|
-
faces += ItsSwiss::MONO_FACE.map { |
|
|
64
|
+
faces += ItsSwiss::MONO_FACE.map { |family_name, ratio| its_swiss_face(family_name, mono, ratio) } if mono
|
|
65
|
+
faces += weights.map { |weight, file| its_swiss_face(family, file, nil, weight: weight) } if family
|
|
58
66
|
|
|
59
67
|
tag.style(faces.join("\n").html_safe) # rubocop:disable Rails/OutputSafety -- every value is a number or a JSON-quoted path
|
|
60
68
|
end
|
|
@@ -107,18 +115,20 @@ module ItsSwiss
|
|
|
107
115
|
|
|
108
116
|
FONT_FORMATS = { ".woff2" => "woff2", ".woff" => "woff", ".ttf" => "truetype", ".otf" => "opentype" }.freeze
|
|
109
117
|
|
|
118
|
+
# With a ratio, a face whose ascent is that ratio and whose descent is
|
|
119
|
+
# nothing; without one, the font under its own name with its own metrics.
|
|
110
120
|
def its_swiss_face(family, file, ratio, weight: nil)
|
|
111
121
|
source = "url(#{asset_path(file).to_json})"
|
|
112
122
|
source += %( format("#{FONT_FORMATS[File.extname(file)]}")) if FONT_FORMATS[File.extname(file)]
|
|
113
|
-
ascent = (ratio * 100).to_f.round(4).to_s.sub(/\.0\z/, "")
|
|
123
|
+
ascent = (ratio * 100).to_f.round(4).to_s.sub(/\.0\z/, "") if ratio
|
|
114
124
|
|
|
115
125
|
[ "@font-face {",
|
|
116
126
|
" font-family: #{family.to_json};",
|
|
117
127
|
(" font-weight: #{weight};" if weight),
|
|
118
128
|
" src: #{source};",
|
|
119
|
-
" ascent-override: #{ascent}%;",
|
|
120
|
-
" descent-override: 0%;",
|
|
121
|
-
" line-gap-override: 0%;",
|
|
129
|
+
(" ascent-override: #{ascent}%;" if ratio),
|
|
130
|
+
(" descent-override: 0%;" if ratio),
|
|
131
|
+
(" line-gap-override: 0%;" if ratio),
|
|
122
132
|
"}" ].compact.join("\n")
|
|
123
133
|
end
|
|
124
134
|
private :its_swiss_face
|
data/lib/its_swiss/version.rb
CHANGED