@kolkrabbi/kol-component 0.170.0 → 0.171.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.171.0",
|
|
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/index.js
CHANGED
|
@@ -22,6 +22,7 @@ export { default as AssetPlaceholder } from './utilities/AssetPlaceholder.jsx'
|
|
|
22
22
|
export { default as Avatar } from './atoms/Avatar.jsx'
|
|
23
23
|
export { default as Badge } from './atoms/Badge.jsx'
|
|
24
24
|
export { default as Button } from './atoms/Button.jsx'
|
|
25
|
+
export { default as CloseButton } from './utilities/CloseButton.jsx'
|
|
25
26
|
export { default as ActionButton } from './atoms/ActionButton.jsx'
|
|
26
27
|
export { default as SizeOrDownload } from './atoms/SizeOrDownload.jsx'
|
|
27
28
|
export { default as SortHeader } from './atoms/SortHeader.jsx'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
3
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
4
|
-
import
|
|
4
|
+
import CloseButton from '../utilities/CloseButton.jsx'
|
|
5
5
|
import usePrefersReducedMotion from '../hooks/usePrefersReducedMotion.js'
|
|
6
6
|
|
|
7
7
|
/* taxonomy-ok: nests kol-icons's Icon (a package import the relative-import
|
|
@@ -197,14 +197,7 @@ export default function ShellDrawer({
|
|
|
197
197
|
{closeSide === 'start' && (
|
|
198
198
|
/* bare glyph, no container (user 2026-08-09: "the X close icon
|
|
199
199
|
* does not need a container") — body ink at rest, emphasis on hover */
|
|
200
|
-
<
|
|
201
|
-
type="button"
|
|
202
|
-
aria-label="Close"
|
|
203
|
-
onClick={onClose}
|
|
204
|
-
className="inline-flex shrink-0 cursor-pointer border-0 bg-transparent p-0 text-body transition-colors duration-150 hover:text-emphasis"
|
|
205
|
-
>
|
|
206
|
-
<Icon name="x" size={18} />
|
|
207
|
-
</button>
|
|
200
|
+
<CloseButton onClick={onClose} size={closeSize} className="shrink-0" />
|
|
208
201
|
)}
|
|
209
202
|
{header != null && <div className="min-w-0 flex-1">{header}</div>}
|
|
210
203
|
{/* A NORMAL ICON BUTTON (user 2026-09-02: *"it should just be like a
|
|
@@ -214,14 +207,7 @@ export default function ShellDrawer({
|
|
|
214
207
|
* the md rung's 32px around a glyph six under it, and it read as an
|
|
215
208
|
* oversized empty square. No override: the rung sets both. */}
|
|
216
209
|
{closeSide !== 'start' && (
|
|
217
|
-
<
|
|
218
|
-
variant="nav"
|
|
219
|
-
size={closeSize}
|
|
220
|
-
iconOnly="x"
|
|
221
|
-
onClick={onClose}
|
|
222
|
-
aria-label="Close"
|
|
223
|
-
className="ml-auto shrink-0"
|
|
224
|
-
/>
|
|
210
|
+
<CloseButton onClick={onClose} size={closeSize} className="ml-auto shrink-0" />
|
|
225
211
|
)}
|
|
226
212
|
</div>
|
|
227
213
|
<div className="flex-1 overflow-y-auto pr-1" style={{ overflowAnchor: 'none' }}>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
|
+
import CloseButton from '../utilities/CloseButton.jsx'
|
|
2
3
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
4
|
|
|
4
5
|
/* taxonomy-ok: nests kol-icons's Icon */
|
|
@@ -36,15 +37,9 @@ export default function TabsRow({ tabs = [], value, onChange, onClose, onMinimis
|
|
|
36
37
|
return (
|
|
37
38
|
<div className="flex items-stretch gap-4 h-10">
|
|
38
39
|
{onClose && (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
aria-label="Close"
|
|
43
|
-
className="text-meta hover:text-emphasis self-center"
|
|
44
|
-
style={{ lineHeight: 0 }}
|
|
45
|
-
>
|
|
46
|
-
<Icon name="x" size={12} />
|
|
47
|
-
</button>
|
|
40
|
+
/* the one close, at the rung whose glyph is the 12 this hand-rolled
|
|
41
|
+
* (2026-09-03) — xs SOLO is 12, so the drawing does not move */
|
|
42
|
+
<CloseButton onClick={onClose} size="xs" className="self-center" />
|
|
48
43
|
)}
|
|
49
44
|
|
|
50
45
|
<div ref={listRef} role="tablist" onKeyDown={onKeyDown} className="flex items-stretch gap-4">
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import Button from '../atoms/Button.jsx'
|
|
2
|
+
import IconFrame from '../atoms/IconFrame.jsx'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CloseButton — the X that dismisses a thing. One component, so there is one.
|
|
6
|
+
*
|
|
7
|
+
* WHY IT EXISTS (user 2026-09-03: *"why are you FUCKING MAKING INDIVIDUAL
|
|
8
|
+
* CHANGES this isnt difficult, this is a button component yes or no"*). It is a
|
|
9
|
+
* Button, and that was the problem: "close" was never a component, it was four
|
|
10
|
+
* props retyped at four call sites, so the four drifted —
|
|
11
|
+
*
|
|
12
|
+
* ShellDrawer Button variant="nav" size="md" (+ a second,
|
|
13
|
+
* hand-rolled <button> with an 18px icon for closeSide="start")
|
|
14
|
+
* FullscreenOverlay Button variant="nav", Button's md default
|
|
15
|
+
* TabsRow a hand-rolled <button> with a 12px icon and its own hover
|
|
16
|
+
* ShellLayout Button variant="outline" quiet size="sm"
|
|
17
|
+
*
|
|
18
|
+
* — three sizes and two variants for one control, and `ShellLayout` was still
|
|
19
|
+
* shipping the boxed outline that the 2026-09-01 one-idiom ruling retired. The
|
|
20
|
+
* ruling was written down and then re-typed wrong three times, which is the
|
|
21
|
+
* `HEADER_ICON` lesson again: a number is advice, a component is the only thing
|
|
22
|
+
* that makes the box unwritable by hand.
|
|
23
|
+
*
|
|
24
|
+
* THE IDIOM, in one place: `variant="nav"` — bare glyph, no box, the wash on
|
|
25
|
+
* hover — at `sm` (26), the same rung as the controls a close usually sits
|
|
26
|
+
* beside. `size` is here because a close in a taller chrome row legitimately
|
|
27
|
+
* takes that row's rung; it is the ONLY thing a call site may vary, and it must
|
|
28
|
+
* be a rung, never an `iconSize`. The glyph follows from the rung.
|
|
29
|
+
*
|
|
30
|
+
* UTILITY, by the placement test (2026-08-09): an X on a canvas alone means
|
|
31
|
+
* nothing — it is only ever worn BY the thing it dismisses, the same row
|
|
32
|
+
* `FullscreenOverlay` is held on. It is also the only tier that works: a close
|
|
33
|
+
* is needed by a utility (`FullscreenOverlay`), a molecule (`ShellDrawer`,
|
|
34
|
+
* `TabsRow`) and a package shell alike, and utilities are the one folder every
|
|
35
|
+
* tier may import while importing only atoms itself.
|
|
36
|
+
*
|
|
37
|
+
* TWO BASES, ONE IDIOM (user 2026-09-03: *"sometimes you dont want states"*).
|
|
38
|
+
* `states` (default true) is a Button — hover wash, press, focus ring — which is
|
|
39
|
+
* what a close in reachable chrome should be. `states={false}` is `IconFrame`,
|
|
40
|
+
* which has NO interactive states by contract: for a close that is decoration
|
|
41
|
+
* over something already dismissible, or one inside a surface that owns the
|
|
42
|
+
* whole hit area, where a lighting-up X is noise. Same glyph, same variant, same
|
|
43
|
+
* rung either way — only the state machine differs, which is exactly the
|
|
44
|
+
* distinction IconFrame was promoted for (2026-08-01).
|
|
45
|
+
*
|
|
46
|
+
* @param {Function} onClick dismiss
|
|
47
|
+
* @param {boolean} states interactive states (default true → Button); false → IconFrame, no states
|
|
48
|
+
* @param {'xs'|'sm'|'md'|'lg'} size the rung (default 'sm'); match the row it sits in
|
|
49
|
+
* @param {string} label accessible name (default 'Close')
|
|
50
|
+
* @param {string} className extra classes — positioning, never chrome
|
|
51
|
+
*/
|
|
52
|
+
export default function CloseButton({ onClick, size = 'sm', label = 'Close', states = true, className = '', ...rest }) {
|
|
53
|
+
if (!states) {
|
|
54
|
+
return (
|
|
55
|
+
<IconFrame
|
|
56
|
+
name="x"
|
|
57
|
+
variant="nav"
|
|
58
|
+
size={size}
|
|
59
|
+
onClick={onClick}
|
|
60
|
+
aria-label={label}
|
|
61
|
+
className={className}
|
|
62
|
+
{...rest}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
return (
|
|
67
|
+
<Button
|
|
68
|
+
variant="nav"
|
|
69
|
+
size={size}
|
|
70
|
+
iconOnly="x"
|
|
71
|
+
onClick={onClick}
|
|
72
|
+
aria-label={label}
|
|
73
|
+
className={className}
|
|
74
|
+
{...rest}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react'
|
|
2
|
-
import
|
|
2
|
+
import CloseButton from './CloseButton.jsx'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* FullscreenOverlay — the scrim + centred sheet every overlay in the repo
|
|
@@ -74,14 +74,7 @@ export default function FullscreenOverlay({ open, onClose, closeButton = true, c
|
|
|
74
74
|
* tap away from the first, and had he kept a box it would have worn
|
|
75
75
|
* `primary`, never `outline`. Same variant as the trigger; the SQUARE
|
|
76
76
|
* is `sm` since 2026-09-03, one size for the one idiom. */
|
|
77
|
-
<
|
|
78
|
-
variant="nav"
|
|
79
|
-
size="sm"
|
|
80
|
-
iconOnly="x"
|
|
81
|
-
className="kol-overlay-close"
|
|
82
|
-
onClick={onClose}
|
|
83
|
-
aria-label="Close"
|
|
84
|
-
/>
|
|
77
|
+
<CloseButton className="kol-overlay-close" onClick={onClose} />
|
|
85
78
|
)}
|
|
86
79
|
{children}
|
|
87
80
|
</div>
|