@kolkrabbi/kol-component 0.25.0 → 0.26.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 +1 -1
- package/src/atoms/Popover.jsx +4 -1
- package/src/hooks/glyphLadders.js +15 -0
- package/src/index.js +1 -1
- package/src/molecules/Dropdown.jsx +24 -31
- package/src/organisms/Table.jsx +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.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/atoms/Popover.jsx
CHANGED
|
@@ -68,8 +68,11 @@ export function usePopover({
|
|
|
68
68
|
middleware.push(
|
|
69
69
|
sizeMw({
|
|
70
70
|
apply({ rects, elements }) {
|
|
71
|
+
/* EXACT width, not a floor (2026-08-09) — "one piece means one
|
|
72
|
+
* width": with minWidth alone, a wide row let the panel outgrow the
|
|
73
|
+
* trigger it claims to continue. Sole consumer is Dropdown. */
|
|
71
74
|
Object.assign(elements.floating.style, {
|
|
72
|
-
|
|
75
|
+
width: `${rects.reference.width}px`,
|
|
73
76
|
})
|
|
74
77
|
},
|
|
75
78
|
})
|
|
@@ -29,6 +29,16 @@ export const SOLO = { sm: 16, md: 20, lg: 24 }
|
|
|
29
29
|
/** Icon beside a label, inside the rung's line box. */
|
|
30
30
|
export const ADJACENT = { sm: 14, md: 16, lg: 18 }
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Indicator glyph — a caret/chevron that DECORATES a control rather than
|
|
34
|
+
* naming it (a dropdown caret, a sort arrow). Pairs 1:1 with the control's
|
|
35
|
+
* mono text rung, one step under ADJACENT: an indicator never outweighs the
|
|
36
|
+
* label it points at. Promoted 2026-08-09 — Table's sort chevron and
|
|
37
|
+
* Dropdown's caret each hand-typed their number (Dropdown took the ADJACENT
|
|
38
|
+
* rung, the oversize the user called): two transcriptions, the folklore
|
|
39
|
+
* threshold. */
|
|
40
|
+
export const INDICATOR = { sm: 12, md: 14, lg: 16 }
|
|
41
|
+
|
|
32
42
|
/**
|
|
33
43
|
* Resolve a glyph size. `solo` picks the ladder; `size` indexes it.
|
|
34
44
|
* Falls back to the md rung so an unknown size never yields undefined.
|
|
@@ -37,3 +47,8 @@ export function glyphSize(size, solo = false) {
|
|
|
37
47
|
const ladder = solo ? SOLO : ADJACENT
|
|
38
48
|
return ladder[size] ?? ladder.md
|
|
39
49
|
}
|
|
50
|
+
|
|
51
|
+
/** Resolve an indicator size. Separate helper — `solo` never applies. */
|
|
52
|
+
export function indicatorSize(size) {
|
|
53
|
+
return INDICATOR[size] ?? INDICATOR.md
|
|
54
|
+
}
|
package/src/index.js
CHANGED
|
@@ -131,7 +131,7 @@ export { GRAPHIC_RAW } from './graphics/graphicData.js'
|
|
|
131
131
|
* took `20`, and neither could reference the rule it was meant to follow.
|
|
132
132
|
* Cross-package imports go through the `@kolkrabbi/*` specifier (ARCHITECTURE
|
|
133
133
|
* §3), so an export is the only way another package can obey the ladder. */
|
|
134
|
-
export { SOLO, ADJACENT, glyphSize } from './hooks/glyphLadders.js'
|
|
134
|
+
export { SOLO, ADJACENT, INDICATOR, glyphSize, indicatorSize } from './hooks/glyphLadders.js'
|
|
135
135
|
|
|
136
136
|
// hooks
|
|
137
137
|
export { default as usePrefersReducedMotion } from './hooks/usePrefersReducedMotion.js'
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react'
|
|
2
2
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
3
|
import { MenuDropdownItem } from './MenuItem.jsx'
|
|
4
4
|
import { PopoverPanel, usePopover } from '../atoms/Popover.jsx'
|
|
5
|
+
import { indicatorSize } from '../hooks/glyphLadders.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Dropdown — trigger IS button chrome (2026-07-08 chrome law).
|
|
@@ -28,7 +29,10 @@ import { PopoverPanel, usePopover } from '../atoms/Popover.jsx'
|
|
|
28
29
|
*/
|
|
29
30
|
|
|
30
31
|
const SIZE_TYPE = { sm: 'kol-mono-12', md: 'kol-mono-14', lg: 'kol-mono-16' }
|
|
31
|
-
|
|
32
|
+
/* Caret size comes from the INDICATOR ladder (glyphLadders.js) — the private
|
|
33
|
+
* map that lived here was a transcription of ADJACENT, which is the wrong
|
|
34
|
+
* ladder for a decoration: it put a caret one rung HEAVIER than the label
|
|
35
|
+
* beside it (2026-08-09 user call). */
|
|
32
36
|
|
|
33
37
|
const LEGACY_VARIANTS = { default: 'primary', subtle: 'primary', minimal: 'outline' }
|
|
34
38
|
|
|
@@ -42,7 +46,6 @@ const Dropdown = ({
|
|
|
42
46
|
className = ''
|
|
43
47
|
}) => {
|
|
44
48
|
const [isOpen, setIsOpen] = useState(defaultOpen)
|
|
45
|
-
const [dropdownWidth, setDropdownWidth] = useState('100px')
|
|
46
49
|
|
|
47
50
|
// sm everywhere unless explicitly overridden (see docblock size law).
|
|
48
51
|
const resolvedSize = size || 'sm'
|
|
@@ -63,23 +66,11 @@ const Dropdown = ({
|
|
|
63
66
|
role: 'listbox',
|
|
64
67
|
})
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (window.innerWidth >= 1024) {
|
|
72
|
-
setDropdownWidth('180px')
|
|
73
|
-
} else if (window.innerWidth >= 768) {
|
|
74
|
-
setDropdownWidth('140px')
|
|
75
|
-
} else {
|
|
76
|
-
setDropdownWidth('100px')
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
updateWidth()
|
|
80
|
-
window.addEventListener('resize', updateWidth)
|
|
81
|
-
return () => window.removeEventListener('resize', updateWidth)
|
|
82
|
-
}, [])
|
|
69
|
+
/* Width belongs to the CALL SITE (2026-08-09 user call — "width without any
|
|
70
|
+
* regard to context"). The viewport-keyed resize listener that handed every
|
|
71
|
+
* dropdown a fixed width by window size is gone: default is hug-content,
|
|
72
|
+
* and the consumer sizes it through className exactly as on Input. The open
|
|
73
|
+
* panel follows the trigger via matchReferenceWidth either way. */
|
|
83
74
|
|
|
84
75
|
const handleSelect = (option) => {
|
|
85
76
|
onChange?.(option.value)
|
|
@@ -100,15 +91,7 @@ const Dropdown = ({
|
|
|
100
91
|
].filter(Boolean).join(' ')
|
|
101
92
|
|
|
102
93
|
return (
|
|
103
|
-
<div
|
|
104
|
-
className={`relative block ${className}`}
|
|
105
|
-
style={{
|
|
106
|
-
...(dropdownWidth && !className.includes('w-full') && {
|
|
107
|
-
width: dropdownWidth,
|
|
108
|
-
minWidth: dropdownWidth
|
|
109
|
-
})
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
94
|
+
<div className={`relative inline-block align-middle ${className}`}>
|
|
112
95
|
<button
|
|
113
96
|
ref={popover.refs.setReference}
|
|
114
97
|
{...popover.getReferenceProps()}
|
|
@@ -118,10 +101,20 @@ const Dropdown = ({
|
|
|
118
101
|
aria-expanded={isOpen}
|
|
119
102
|
data-state={isOpen ? 'open' : 'closed'}
|
|
120
103
|
>
|
|
121
|
-
|
|
104
|
+
{/* every option's label rides along hidden so the trigger is as wide
|
|
105
|
+
* as its widest value — the panel matches the trigger's width, so
|
|
106
|
+
* trigger and list stay one piece at every selection */}
|
|
107
|
+
<span className="kol-dd-label">
|
|
108
|
+
<span>{currentOption?.label}</span>
|
|
109
|
+
{options.map((option) => (
|
|
110
|
+
<span key={option.value} className="kol-dd-ghost" aria-hidden="true">
|
|
111
|
+
{option.label}
|
|
112
|
+
</span>
|
|
113
|
+
))}
|
|
114
|
+
</span>
|
|
122
115
|
{/* chrome lives in .kol-dd-caret (trailing edge + open-state flip) —
|
|
123
116
|
* keyed off the trigger's data-state, no inline styles */}
|
|
124
|
-
<Icon name="chevron-down" size={
|
|
117
|
+
<Icon name="chevron-down" size={indicatorSize(resolvedSize)} className="kol-dd-caret" />
|
|
125
118
|
</button>
|
|
126
119
|
|
|
127
120
|
<PopoverPanel
|
package/src/organisms/Table.jsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useMemo, useState } from 'react'
|
|
2
2
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
3
|
+
import { INDICATOR } from '../hooks/glyphLadders.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Table — data table.
|
|
@@ -79,7 +80,7 @@ const Table = ({ caption, columns, rows, variant = 'default', className = '', wi
|
|
|
79
80
|
{column.header}
|
|
80
81
|
<Icon
|
|
81
82
|
name={sort.key === column.accessor && sort.dir === 'desc' ? 'chevron-down' : 'chevron-up'}
|
|
82
|
-
size={
|
|
83
|
+
size={INDICATOR.sm}
|
|
83
84
|
className={sort.key === column.accessor ? 'opacity-100' : 'opacity-0 group-hover:opacity-40'}
|
|
84
85
|
/>
|
|
85
86
|
</button>
|