@kolkrabbi/kol-component 0.19.0 → 0.20.1
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.
- package/package.json +1 -1
- package/src/atoms/Button.jsx +15 -3
- package/src/atoms/IconFrame.jsx +4 -1
- package/src/atoms/Input.jsx +7 -2
- package/src/hooks/glyphLadders.js +39 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/atoms/Button.jsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isValidElement } from 'react'
|
|
2
2
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
|
+
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Button — canonical KOL button. Emits kol-btn* classes (CSS in @kol/theme).
|
|
@@ -20,7 +21,8 @@ import { Icon } from '@kolkrabbi/kol-icons'
|
|
|
20
21
|
* @param {string} props.iconOnlyHover - Icon to show on hover (icon-only)
|
|
21
22
|
* @param {boolean} props.animateIcon - Disable default hover states to focus on icon animation
|
|
22
23
|
* @param {boolean} props.quiet - Dimmed at rest, brightens on hover; stays dimmed when disabled. For secondary icon-only chrome.
|
|
23
|
-
* @param {number} props.iconSize - Size of the icon in pixels (default: auto by size)
|
|
24
|
+
* @param {number} props.iconSize - Size of the icon in pixels (default: auto by size — SOLO when iconOnly, ADJACENT otherwise)
|
|
25
|
+
* @param {'sm'|'full'} props.radius - sm (default, the system's radius token) | full (a full round). Two values, nothing between — mirrors IconFrame, and a round control is its own chrome idiom (edge-straddling controls, avatars), the only sanctioned exception to the hard radius invariant.
|
|
24
26
|
* @param {number} props.iconGap - Gap between icon and text (default: 8)
|
|
25
27
|
* @param {string} props.href - Link destination (makes it an <a>)
|
|
26
28
|
* @param {Function} props.onClick - Click handler (makes it a <button>)
|
|
@@ -42,6 +44,7 @@ const Button = ({
|
|
|
42
44
|
iconRightHover,
|
|
43
45
|
iconOnly,
|
|
44
46
|
iconOnlyHover,
|
|
47
|
+
radius = 'sm',
|
|
45
48
|
animateIcon = false,
|
|
46
49
|
quiet = false,
|
|
47
50
|
iconSize,
|
|
@@ -57,7 +60,11 @@ const Button = ({
|
|
|
57
60
|
pressed,
|
|
58
61
|
...props
|
|
59
62
|
}) => {
|
|
60
|
-
|
|
63
|
+
// Two ladders, split on whether a label sits beside the glyph. An icon-only
|
|
64
|
+
// button is a solo glyph in a pinned square, so it takes SOLO (16/20/24) —
|
|
65
|
+
// it took the text-adjacent ladder until component 0.20.0, which put a 14px
|
|
66
|
+
// glyph in a 28px square at `sm`. `iconSize` still overrides either.
|
|
67
|
+
const resolvedIconSize = iconSize ?? glyphSize(size, Boolean(iconOnly))
|
|
61
68
|
|
|
62
69
|
// `control` is a legacy alias for `ghost` (kept so web call-sites passing
|
|
63
70
|
// variant="control" keep working post-migration).
|
|
@@ -97,7 +104,12 @@ const Button = ({
|
|
|
97
104
|
// .kol-btn-icon replaces the old iconOnly INLINE style — inline display
|
|
98
105
|
// beat every consumer utility (lg:hidden could never hide the button).
|
|
99
106
|
const iconOnlyClass = iconOnly ? 'kol-btn-icon' : ''
|
|
100
|
-
|
|
107
|
+
|
|
108
|
+
// `sm` is the default and carries no class — it's on .kol-btn itself.
|
|
109
|
+
// The rule for `full` is shared with .kol-icon-frame-radius-full, one
|
|
110
|
+
// selector, so the two controls can never disagree on the value.
|
|
111
|
+
const radiusClass = radius === 'full' ? 'kol-btn-radius-full' : ''
|
|
112
|
+
const combinedClass = `kol-btn ${variantClass} ${sizeClass} ${animateClass} ${quietClass} ${pressedClass} ${iconOnlyClass} ${radiusClass} ${className}`.trim().replace(/\s+/g, ' ')
|
|
101
113
|
|
|
102
114
|
// Render icon with optional hover state
|
|
103
115
|
const renderIcon = (iconName, iconHoverName) => {
|
package/src/atoms/IconFrame.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
2
|
+
import { SOLO } from '../hooks/glyphLadders.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* IconFrame — a STATIC square frame holding one icon.
|
|
@@ -51,7 +52,9 @@ import { Icon } from '@kolkrabbi/kol-icons'
|
|
|
51
52
|
* square is unaffected; only the centred glyph moves.
|
|
52
53
|
* @param {string} className escape hatch
|
|
53
54
|
*/
|
|
54
|
-
|
|
55
|
+
// The solo-glyph ladder, from its one source. This was a local transcription
|
|
56
|
+
// until component 0.20.0 — see hooks/glyphLadders.js for why that mattered.
|
|
57
|
+
const GLYPH = SOLO
|
|
55
58
|
|
|
56
59
|
export default function IconFrame({
|
|
57
60
|
name,
|
package/src/atoms/Input.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
2
|
+
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Input — single-input atom built on the .kol-control shell.
|
|
@@ -31,7 +32,6 @@ import { Icon } from '@kolkrabbi/kol-icons'
|
|
|
31
32
|
*/
|
|
32
33
|
|
|
33
34
|
const SIZE_TYPE = { sm: 'kol-mono-12', md: 'kol-mono-14', lg: 'kol-mono-16' }
|
|
34
|
-
const ICON_SIZE = { sm: 14, md: 14, lg: 18 }
|
|
35
35
|
|
|
36
36
|
export default function Input({
|
|
37
37
|
type = 'text',
|
|
@@ -53,7 +53,12 @@ export default function Input({
|
|
|
53
53
|
}) {
|
|
54
54
|
const isNumber = type === 'number'
|
|
55
55
|
const fixedChars = typeof chars === 'number'
|
|
56
|
-
|
|
56
|
+
// The text-adjacent ladder — an Input's icon sits in the rung's line box
|
|
57
|
+
// beside the value, exactly like a labelled Button's. `.kol-control-*` and
|
|
58
|
+
// `.kol-btn-*` carry identical padding + type per rung, so the glyph is the
|
|
59
|
+
// same too. This was a local ICON_SIZE with `md: 14` until 0.20.1, the last
|
|
60
|
+
// of the four transcriptions (sm and lg had always agreed).
|
|
61
|
+
const resolvedIconSize = iconSize ?? glyphSize(size)
|
|
57
62
|
|
|
58
63
|
// ghost folds into outline (2026-07-08 chrome law): one secondary treatment.
|
|
59
64
|
const resolvedVariant = variant === 'ghost' ? 'outline' : variant
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE two glyph ladders. One source for the sizes every icon-bearing control
|
|
3
|
+
* resolves against.
|
|
4
|
+
*
|
|
5
|
+
* Plain constants, not hooks — they live here because src/hooks is the
|
|
6
|
+
* taxonomy's only non-component folder (same reason as cssVar.js).
|
|
7
|
+
*
|
|
8
|
+
* The ladders split on ONE question: is there a label beside the glyph?
|
|
9
|
+
*
|
|
10
|
+
* SOLO an icon alone in a pinned square (28/32/36) — takes the room
|
|
11
|
+
* ADJACENT an icon inside a rung's line box, beside a label
|
|
12
|
+
*
|
|
13
|
+
* Stated in the DS before this file existed — ThemeToggle.jsx:40 ("solo
|
|
14
|
+
* 16/20/24, the pinned-square pairing") and IconFrame.jsx ("the solo-glyph
|
|
15
|
+
* ladder against the pinned squares 28/32/36"). This file is where they stop
|
|
16
|
+
* being transcribed.
|
|
17
|
+
*
|
|
18
|
+
* Why it exists: the same two ladders were re-typed in four places
|
|
19
|
+
* (Button, IconFrame, Input, Tag) and had already drifted. Button's icon-only
|
|
20
|
+
* branch took the ADJACENT ladder — a 14px glyph in a 28px square where the
|
|
21
|
+
* law says 16 — which is exactly what independent transcriptions produce.
|
|
22
|
+
* framework 0.10.3 fixed the mirror of this bug (hop-bare took SOLO while
|
|
23
|
+
* carrying a label) and nothing connected the two.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** Icon alone in a pinned square. Pairs with squares 28 · 32 · 36. */
|
|
27
|
+
export const SOLO = { sm: 16, md: 20, lg: 24 }
|
|
28
|
+
|
|
29
|
+
/** Icon beside a label, inside the rung's line box. */
|
|
30
|
+
export const ADJACENT = { sm: 14, md: 16, lg: 18 }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resolve a glyph size. `solo` picks the ladder; `size` indexes it.
|
|
34
|
+
* Falls back to the md rung so an unknown size never yields undefined.
|
|
35
|
+
*/
|
|
36
|
+
export function glyphSize(size, solo = false) {
|
|
37
|
+
const ladder = solo ? SOLO : ADJACENT
|
|
38
|
+
return ladder[size] ?? ladder.md
|
|
39
|
+
}
|