@kolkrabbi/kol-component 0.5.0 → 0.7.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 +5 -3
- package/src/atoms/Button.jsx +9 -5
- package/src/atoms/Input.jsx +9 -6
- package/src/atoms/Textarea.jsx +36 -5
- package/src/atoms/ToggleSwitch.jsx +31 -4
- package/src/chess/ChessPiece.jsx +191 -0
- package/src/chess/apparatus/AlternativeControlsMock.jsx +460 -0
- package/src/chess/apparatus/ChessAnalysisLayout.jsx +24 -0
- package/src/chess/apparatus/ChessBoard.jsx +210 -0
- package/src/chess/apparatus/ChessBoardFullscreen.jsx +49 -0
- package/src/chess/apparatus/ChessBoardWithControls.jsx +41 -0
- package/src/chess/apparatus/ChessBoardWithSidebar.jsx +122 -0
- package/src/chess/apparatus/ChessSidebar.jsx +131 -0
- package/src/chess/apparatus/GameArchiveTable.jsx +493 -0
- package/src/chess/apparatus/GameSelector.jsx +47 -0
- package/src/chess/apparatus/NotationPanel.jsx +70 -0
- package/src/chess/apparatus/PlaybackControls.jsx +52 -0
- package/src/chess/apparatus/VariationTree.jsx +137 -0
- package/src/chess/assets/chess-extra-set/set-1/bishop-1.svg +6 -0
- package/src/chess/assets/chess-extra-set/set-1/bishop.svg +6 -0
- package/src/chess/assets/chess-extra-set/set-1/king-1.svg +9 -0
- package/src/chess/assets/chess-extra-set/set-1/king.svg +7 -0
- package/src/chess/assets/chess-extra-set/set-1/knight-1.svg +8 -0
- package/src/chess/assets/chess-extra-set/set-1/knight.svg +7 -0
- package/src/chess/assets/chess-extra-set/set-1/pawn-1.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-1/pawn.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-1/queen-1.svg +11 -0
- package/src/chess/assets/chess-extra-set/set-1/queen.svg +6 -0
- package/src/chess/assets/chess-extra-set/set-1/rook-1.svg +7 -0
- package/src/chess/assets/chess-extra-set/set-1/rook.svg +11 -0
- package/src/chess/assets/chess-extra-set/set-2/bishop-1.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/bishop.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/king-1.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/king.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/knight-1.svg +5 -0
- package/src/chess/assets/chess-extra-set/set-2/knight.svg +5 -0
- package/src/chess/assets/chess-extra-set/set-2/pawn-1.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/pawn.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/queen-1.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/queen.svg +4 -0
- package/src/chess/assets/chess-extra-set/set-2/rook-1.svg +5 -0
- package/src/chess/assets/chess-extra-set/set-2/rook.svg +5 -0
- package/src/chess/assets/chess-extra-set/set-3/bishop-1.svg +10 -0
- package/src/chess/assets/chess-extra-set/set-3/bishop.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-3/king-1.svg +12 -0
- package/src/chess/assets/chess-extra-set/set-3/king.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-3/knight-1.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-3/knight.svg +10 -0
- package/src/chess/assets/chess-extra-set/set-3/pawn-1.svg +10 -0
- package/src/chess/assets/chess-extra-set/set-3/pawn.svg +10 -0
- package/src/chess/assets/chess-extra-set/set-3/queen-1.svg +10 -0
- package/src/chess/assets/chess-extra-set/set-3/queen.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-3/rook-1.svg +3 -0
- package/src/chess/assets/chess-extra-set/set-3/rook.svg +11 -0
- package/src/chess/assets/chess-vector-set/ABoard.svg +164 -0
- package/src/chess/assets/chess-vector-set/BBiskup.svg +12 -0
- package/src/chess/assets/chess-vector-set/BKing.svg +15 -0
- package/src/chess/assets/chess-vector-set/BKnight.svg +13 -0
- package/src/chess/assets/chess-vector-set/BPawn.svg +7 -0
- package/src/chess/assets/chess-vector-set/BQueen.svg +6 -0
- package/src/chess/assets/chess-vector-set/BRook.svg +12 -0
- package/src/chess/assets/chess-vector-set/WBiskup.svg +14 -0
- package/src/chess/assets/chess-vector-set/WKing.svg +13 -0
- package/src/chess/assets/chess-vector-set/WKnight.svg +10 -0
- package/src/chess/assets/chess-vector-set/WPawn.svg +8 -0
- package/src/chess/assets/chess-vector-set/WQueen.svg +17 -0
- package/src/chess/assets/chess-vector-set/WRook.svg +13 -0
- package/src/chess/context/ChessControlsContext.jsx +379 -0
- package/src/chess/dashboards/ChessHero.jsx +303 -0
- package/src/chess/index.js +32 -0
- package/src/chess/utils/parsePgnTree.js +97 -0
- package/src/dashboards/cards/DashAlertCard.jsx +44 -0
- package/src/dashboards/cards/DashChartCard.jsx +44 -0
- package/src/dashboards/cards/DashFeaturedCard.jsx +42 -0
- package/src/dashboards/cards/DashListCard.jsx +87 -0
- package/src/dashboards/cards/DashMetricCard.jsx +59 -0
- package/src/dashboards/cards/DashSlotCard.jsx +45 -0
- package/src/dashboards/cards/DashStackedBarCard.jsx +70 -0
- package/src/dashboards/cards/DashTableCard.jsx +31 -0
- package/src/dashboards/cards/_shared/CardHeader.jsx +15 -0
- package/src/dashboards/cards/_shared/LegendRow.jsx +25 -0
- package/src/dashboards/charts/Candlestick.jsx +79 -0
- package/src/dashboards/charts/DonutChart.jsx +87 -0
- package/src/dashboards/charts/Heatmap.jsx +79 -0
- package/src/dashboards/charts/Histogram.jsx +56 -0
- package/src/dashboards/charts/LineChart.jsx +157 -0
- package/src/dashboards/charts/ScatterPlot.jsx +93 -0
- package/src/dashboards/charts/Sparkline.jsx +63 -0
- package/src/dashboards/index.js +28 -0
- package/src/dashboards/layout/DashboardGrid.jsx +30 -0
- package/src/dashboards/layout/GridCard.jsx +44 -0
- package/src/dashboards/shared/DashTooltip.jsx +6 -0
- package/src/dashboards/shared/formatMetric.js +26 -0
- package/src/dashboards/shared/useChartTooltip.js +25 -0
- package/src/dashboards/shared/useCountUp.js +107 -0
- package/src/molecules/Dropdown.jsx +50 -96
- package/src/molecules/Slider.jsx +4 -14
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useState, useCallback, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
const useChartTooltip = () => {
|
|
4
|
+
const [activeIndex, setActiveIndex] = useState(null)
|
|
5
|
+
const containerRef = useRef(null)
|
|
6
|
+
|
|
7
|
+
const containerHandlers = {
|
|
8
|
+
onMouseMove: (e) => {
|
|
9
|
+
if (!containerRef.current) return
|
|
10
|
+
const rect = containerRef.current.getBoundingClientRect()
|
|
11
|
+
containerRef.current.style.setProperty('--tx', `${e.clientX - rect.left}px`)
|
|
12
|
+
containerRef.current.style.setProperty('--ty', `${e.clientY - rect.top}px`)
|
|
13
|
+
},
|
|
14
|
+
onMouseLeave: () => setActiveIndex(null)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const handlers = useCallback((index) => ({
|
|
18
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
19
|
+
onMouseLeave: () => setActiveIndex(null)
|
|
20
|
+
}), [])
|
|
21
|
+
|
|
22
|
+
return { activeIndex, handlers, containerHandlers, containerRef }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default useChartTooltip
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
const parseNumeric = (value) => {
|
|
4
|
+
const str = String(value)
|
|
5
|
+
const match = str.match(/^([^0-9]*?)([\d,.]+)(.*?)$/)
|
|
6
|
+
if (!match) return null
|
|
7
|
+
const prefix = match[1]
|
|
8
|
+
const numStr = match[2]
|
|
9
|
+
const suffix = match[3]
|
|
10
|
+
const num = parseFloat(numStr.replace(/,/g, ''))
|
|
11
|
+
if (isNaN(num)) return null
|
|
12
|
+
const hasCommas = numStr.includes(',')
|
|
13
|
+
const decimalMatch = numStr.match(/\.(\d+)/)
|
|
14
|
+
const decimals = decimalMatch ? decimalMatch[1].length : 0
|
|
15
|
+
return { prefix, num, suffix, hasCommas, decimals }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const formatNumber = (n, hasCommas, decimals) => {
|
|
19
|
+
const fixed = n.toFixed(decimals)
|
|
20
|
+
if (!hasCommas) return fixed
|
|
21
|
+
const [intPart, decPart] = fixed.split('.')
|
|
22
|
+
const withCommas = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
23
|
+
return decPart ? `${withCommas}.${decPart}` : withCommas
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const useCountUp = (targetValue, { duration = 600, enabled = true } = {}) => {
|
|
27
|
+
const [displayValue, setDisplayValue] = useState(targetValue)
|
|
28
|
+
const ref = useRef(null)
|
|
29
|
+
const hasEnteredRef = useRef(false)
|
|
30
|
+
const prevTargetRef = useRef(targetValue)
|
|
31
|
+
const rafRef = useRef(null)
|
|
32
|
+
const elRef = useRef(null)
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!enabled) {
|
|
36
|
+
setDisplayValue(targetValue)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const animate = (from, to) => {
|
|
41
|
+
const parsed = parseNumeric(to)
|
|
42
|
+
if (!parsed) {
|
|
43
|
+
setDisplayValue(to)
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const parsedFrom = parseNumeric(from)
|
|
48
|
+
const startNum = parsedFrom ? parsedFrom.num : 0
|
|
49
|
+
const endNum = parsed.num
|
|
50
|
+
const startTime = performance.now()
|
|
51
|
+
|
|
52
|
+
const step = (now) => {
|
|
53
|
+
const elapsed = now - startTime
|
|
54
|
+
const t = Math.min(elapsed / duration, 1)
|
|
55
|
+
const eased = t * (2 - t) // ease-out quadratic
|
|
56
|
+
const current = startNum + (endNum - startNum) * eased
|
|
57
|
+
const formatted = `${parsed.prefix}${formatNumber(current, parsed.hasCommas, parsed.decimals)}${parsed.suffix}`
|
|
58
|
+
setDisplayValue(formatted)
|
|
59
|
+
if (t < 1) {
|
|
60
|
+
rafRef.current = requestAnimationFrame(step)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current)
|
|
65
|
+
rafRef.current = requestAnimationFrame(step)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// On target change while already visible
|
|
69
|
+
if (hasEnteredRef.current && prevTargetRef.current !== targetValue) {
|
|
70
|
+
animate(prevTargetRef.current, targetValue)
|
|
71
|
+
prevTargetRef.current = targetValue
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
prevTargetRef.current = targetValue
|
|
76
|
+
|
|
77
|
+
// IntersectionObserver for first entry
|
|
78
|
+
if (hasEnteredRef.current) return
|
|
79
|
+
|
|
80
|
+
const el = elRef.current
|
|
81
|
+
if (!el) {
|
|
82
|
+
setDisplayValue(targetValue)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const observer = new IntersectionObserver(
|
|
87
|
+
([entry]) => {
|
|
88
|
+
if (entry.isIntersecting && !hasEnteredRef.current) {
|
|
89
|
+
hasEnteredRef.current = true
|
|
90
|
+
animate('0', targetValue)
|
|
91
|
+
observer.disconnect()
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{ threshold: 0.1 }
|
|
95
|
+
)
|
|
96
|
+
observer.observe(el)
|
|
97
|
+
|
|
98
|
+
return () => {
|
|
99
|
+
observer.disconnect()
|
|
100
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current)
|
|
101
|
+
}
|
|
102
|
+
}, [targetValue, duration, enabled])
|
|
103
|
+
|
|
104
|
+
return { displayValue, ref: elRef }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default useCountUp
|
|
@@ -3,20 +3,34 @@ import { Icon } from '@kolkrabbi/kol-icons'
|
|
|
3
3
|
import { MenuDropdownItem } from './MenuItem.jsx'
|
|
4
4
|
import { PopoverPanel, usePopover } from '../atoms/Popover.jsx'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Dropdown — trigger IS button chrome (2026-07-08 chrome law).
|
|
8
|
+
*
|
|
9
|
+
* The trigger emits `kol-btn kol-btn-{variant} kol-btn-{size}` so it renders
|
|
10
|
+
* pixel-identical to a Button of the same variant/size — fills, hover,
|
|
11
|
+
* active, focus ring all come from the button rules in kol-theme.
|
|
12
|
+
* `.kol-dd-*` classes only add trigger layout + the open/panel fusion.
|
|
13
|
+
*
|
|
14
|
+
* variant="primary" (default) — filled trigger; open panel continues the
|
|
15
|
+
* same fill (one piece: no border, no gap, hairline divider inside)
|
|
16
|
+
* variant="outline" — bordered trigger; open panel carries the
|
|
17
|
+
* same border, trigger's bottom edge acts as the divider
|
|
18
|
+
*
|
|
19
|
+
* Legacy aliases (pre-law variants, kept so call-sites don't break):
|
|
20
|
+
* default → primary · subtle → primary · minimal → outline
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const SIZE_TYPE = { sm: 'kol-mono-12', md: 'kol-mono-14', lg: 'kol-mono-16' }
|
|
24
|
+
const ICON_SIZE = { sm: 14, md: 16, lg: 18 }
|
|
25
|
+
|
|
26
|
+
const LEGACY_VARIANTS = { default: 'primary', subtle: 'primary', minimal: 'outline' }
|
|
13
27
|
|
|
14
28
|
const Dropdown = ({
|
|
15
29
|
options = [],
|
|
16
30
|
value,
|
|
17
31
|
onChange,
|
|
18
32
|
size,
|
|
19
|
-
variant = '
|
|
33
|
+
variant = 'primary',
|
|
20
34
|
defaultOpen = false,
|
|
21
35
|
className = ''
|
|
22
36
|
}) => {
|
|
@@ -24,15 +38,17 @@ const Dropdown = ({
|
|
|
24
38
|
const [resolvedSize, setResolvedSize] = useState('md')
|
|
25
39
|
const [dropdownWidth, setDropdownWidth] = useState('100px')
|
|
26
40
|
|
|
41
|
+
const resolvedVariant = LEGACY_VARIANTS[variant] || variant
|
|
42
|
+
|
|
27
43
|
/* Floating-ui popover. `flip: false` keeps the panel below the button
|
|
28
|
-
* — the seamless
|
|
29
|
-
*
|
|
44
|
+
* — the seamless fused edge between trigger and panel assumes the panel
|
|
45
|
+
* sits below; flipping above would visually disconnect them.
|
|
30
46
|
* `matchReferenceWidth: true` pins panel min-width to the button. */
|
|
31
47
|
const popover = usePopover({
|
|
32
48
|
open: isOpen,
|
|
33
49
|
onOpenChange: setIsOpen,
|
|
34
50
|
placement: 'bottom-start',
|
|
35
|
-
offset:
|
|
51
|
+
offset: -1,
|
|
36
52
|
flip: false,
|
|
37
53
|
matchReferenceWidth: true,
|
|
38
54
|
role: 'listbox',
|
|
@@ -67,63 +83,23 @@ const Dropdown = ({
|
|
|
67
83
|
}
|
|
68
84
|
}, [size])
|
|
69
85
|
|
|
70
|
-
// Width management
|
|
86
|
+
// Width management — 100px mobile, 140px tablet, 180px desktop
|
|
71
87
|
useEffect(() => {
|
|
72
88
|
const updateWidth = () => {
|
|
73
89
|
if (typeof window === 'undefined') return
|
|
74
90
|
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
setDropdownWidth('180px')
|
|
82
|
-
} else if (window.innerWidth >= 768) {
|
|
83
|
-
setDropdownWidth('140px')
|
|
84
|
-
} else {
|
|
85
|
-
setDropdownWidth('100px')
|
|
86
|
-
}
|
|
91
|
+
if (window.innerWidth >= 1024) {
|
|
92
|
+
setDropdownWidth('180px')
|
|
93
|
+
} else if (window.innerWidth >= 768) {
|
|
94
|
+
setDropdownWidth('140px')
|
|
95
|
+
} else {
|
|
96
|
+
setDropdownWidth('100px')
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
99
|
updateWidth()
|
|
90
100
|
window.addEventListener('resize', updateWidth)
|
|
91
101
|
return () => window.removeEventListener('resize', updateWidth)
|
|
92
|
-
}, [
|
|
93
|
-
|
|
94
|
-
const metrics = SIZE_MAP[resolvedSize] || SIZE_MAP.md
|
|
95
|
-
|
|
96
|
-
// Variant-specific styles
|
|
97
|
-
const variantStyles = {
|
|
98
|
-
default: {
|
|
99
|
-
border: '1px solid var(--kol-border-default)',
|
|
100
|
-
borderRadius: isOpen
|
|
101
|
-
? `${metrics.radius}px ${metrics.radius}px 0 0`
|
|
102
|
-
: `${metrics.radius}px`,
|
|
103
|
-
backgroundColor: 'var(--kol-surface-primary)',
|
|
104
|
-
padding: `${metrics.paddingY}px ${metrics.paddingX}px`
|
|
105
|
-
},
|
|
106
|
-
minimal: {
|
|
107
|
-
border: 'none',
|
|
108
|
-
borderRadius: '0',
|
|
109
|
-
backgroundColor: 'transparent',
|
|
110
|
-
padding: '0',
|
|
111
|
-
height: '24px',
|
|
112
|
-
display: 'flex',
|
|
113
|
-
alignItems: 'center'
|
|
114
|
-
},
|
|
115
|
-
subtle: {
|
|
116
|
-
/* 1px transparent border so total height matches Button + Input + the
|
|
117
|
-
* other shared-control atoms (which have a transparent 1px border for
|
|
118
|
-
* hover/focus consistency). Without this, subtle is 2px shorter. */
|
|
119
|
-
border: '1px solid transparent',
|
|
120
|
-
borderRadius: isOpen ? '4px 4px 0 0' : '4px',
|
|
121
|
-
backgroundColor: 'var(--kol-surface-secondary)',
|
|
122
|
-
padding: `${metrics.paddingY}px ${metrics.paddingX}px`
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const styles = variantStyles[variant] || variantStyles.default
|
|
102
|
+
}, [])
|
|
127
103
|
|
|
128
104
|
const handleSelect = (option) => {
|
|
129
105
|
onChange?.(option.value)
|
|
@@ -132,11 +108,20 @@ const Dropdown = ({
|
|
|
132
108
|
|
|
133
109
|
const currentOption = options.find((opt) => opt.value === value) || options[0]
|
|
134
110
|
|
|
111
|
+
const triggerCls = [
|
|
112
|
+
'kol-btn',
|
|
113
|
+
`kol-btn-${resolvedVariant}`,
|
|
114
|
+
`kol-btn-${resolvedSize}`,
|
|
115
|
+
SIZE_TYPE[resolvedSize],
|
|
116
|
+
'kol-dd-trigger',
|
|
117
|
+
isOpen && 'kol-dd-trigger--open',
|
|
118
|
+
].filter(Boolean).join(' ')
|
|
119
|
+
|
|
135
120
|
return (
|
|
136
121
|
<div
|
|
137
122
|
className={`relative block ${className}`}
|
|
138
123
|
style={{
|
|
139
|
-
...(
|
|
124
|
+
...(dropdownWidth && !className.includes('w-full') && {
|
|
140
125
|
width: dropdownWidth,
|
|
141
126
|
minWidth: dropdownWidth
|
|
142
127
|
})
|
|
@@ -146,26 +131,15 @@ const Dropdown = ({
|
|
|
146
131
|
ref={popover.refs.setReference}
|
|
147
132
|
{...popover.getReferenceProps()}
|
|
148
133
|
type="button"
|
|
149
|
-
className={
|
|
150
|
-
style={{
|
|
151
|
-
border: styles.border,
|
|
152
|
-
borderRadius: styles.borderRadius,
|
|
153
|
-
backgroundColor: styles.backgroundColor,
|
|
154
|
-
color: 'var(--kol-surface-on-primary)',
|
|
155
|
-
padding: styles.padding,
|
|
156
|
-
transition: 'background-color 0.2s, color 0.2s, border-color 0.2s',
|
|
157
|
-
...(variant === 'minimal' && {
|
|
158
|
-
height: styles.height,
|
|
159
|
-
}),
|
|
160
|
-
}}
|
|
134
|
+
className={triggerCls}
|
|
161
135
|
aria-haspopup="listbox"
|
|
162
136
|
aria-expanded={isOpen}
|
|
163
137
|
data-state={isOpen ? 'open' : 'closed'}
|
|
164
138
|
>
|
|
165
|
-
<span
|
|
139
|
+
<span>{currentOption?.label}</span>
|
|
166
140
|
<Icon
|
|
167
141
|
name="chevron-down"
|
|
168
|
-
size={
|
|
142
|
+
size={ICON_SIZE[resolvedSize]}
|
|
169
143
|
className="ml-auto"
|
|
170
144
|
style={{
|
|
171
145
|
transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
@@ -178,29 +152,9 @@ const Dropdown = ({
|
|
|
178
152
|
popover={popover}
|
|
179
153
|
panel={false}
|
|
180
154
|
focus={false}
|
|
181
|
-
|
|
182
|
-
backgroundColor: variant === 'minimal'
|
|
183
|
-
? 'var(--kol-surface-primary)'
|
|
184
|
-
: styles.backgroundColor,
|
|
185
|
-
color: 'var(--kol-surface-on-primary)',
|
|
186
|
-
border: variant === 'subtle' ? 'none' : styles.border,
|
|
187
|
-
borderRadius: variant === 'minimal'
|
|
188
|
-
? '0'
|
|
189
|
-
: (variant === 'subtle'
|
|
190
|
-
? '0 0 4px 4px'
|
|
191
|
-
: `0 0 ${metrics.panelRadius}px ${metrics.panelRadius}px`),
|
|
192
|
-
}}
|
|
155
|
+
className={`kol-dd-panel kol-dd-panel--${resolvedVariant}`}
|
|
193
156
|
>
|
|
194
|
-
{
|
|
195
|
-
<div style={{ padding: `0 ${metrics.paddingX}px` }}>
|
|
196
|
-
<div
|
|
197
|
-
style={{
|
|
198
|
-
height: '1px',
|
|
199
|
-
backgroundColor: 'var(--kol-border-default)'
|
|
200
|
-
}}
|
|
201
|
-
/>
|
|
202
|
-
</div>
|
|
203
|
-
)}
|
|
157
|
+
{resolvedVariant === 'primary' && <div className="kol-dd-div" />}
|
|
204
158
|
|
|
205
159
|
<div className="flex max-h-[300px] flex-col items-stretch overflow-y-auto" role="listbox">
|
|
206
160
|
{options.map((option) => {
|
package/src/molecules/Slider.jsx
CHANGED
|
@@ -4,11 +4,9 @@ import Input from '../atoms/Input.jsx'
|
|
|
4
4
|
/**
|
|
5
5
|
* Slider — range slider with label and an editable value readout.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* inline controls). PRESERVED from web.
|
|
11
|
-
* subtle — filled rounded chip; for inspector-style controls.
|
|
7
|
+
* One bare inline row: label · track · editable readout. (Bordered
|
|
8
|
+
* `default` and chip `subtle` variants retired 2026-07-08 — minimal is
|
|
9
|
+
* the only slider.)
|
|
12
10
|
*
|
|
13
11
|
* The value readout is an editable <Input> (type a value, commit on
|
|
14
12
|
* blur / Enter, revert on Escape). Track color is exposed as the
|
|
@@ -21,7 +19,6 @@ import Input from '../atoms/Input.jsx'
|
|
|
21
19
|
* @param {number} props.max - Maximum value
|
|
22
20
|
* @param {number} props.value - Current value
|
|
23
21
|
* @param {Function} props.onChange - Change handler
|
|
24
|
-
* @param {'default'|'minimal'|'subtle'} props.variant - Visual variant (default: 'default')
|
|
25
22
|
* @param {string} props.className - Additional wrapper classes
|
|
26
23
|
* @param {number} props.displayWidth - Width of the value readout, in characters (default: 6)
|
|
27
24
|
* @param {string} props.fontSize - Font size for label/value (e.g., '11px')
|
|
@@ -34,7 +31,6 @@ const Slider = ({
|
|
|
34
31
|
max = 100,
|
|
35
32
|
value = 0,
|
|
36
33
|
onChange,
|
|
37
|
-
variant = 'default',
|
|
38
34
|
className = '',
|
|
39
35
|
displayWidth = 6,
|
|
40
36
|
fontSize,
|
|
@@ -47,12 +43,6 @@ const Slider = ({
|
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
|
|
50
|
-
const variantClass = variant === 'minimal'
|
|
51
|
-
? 'control-slider-minimal'
|
|
52
|
-
: variant === 'subtle'
|
|
53
|
-
? 'control-slider-subtle'
|
|
54
|
-
: 'control-slider'
|
|
55
|
-
|
|
56
46
|
const decimals = useMemo(() => {
|
|
57
47
|
if (formatValue) return null
|
|
58
48
|
if (!Number.isFinite(step)) return 0
|
|
@@ -94,7 +84,7 @@ const Slider = ({
|
|
|
94
84
|
}
|
|
95
85
|
|
|
96
86
|
return (
|
|
97
|
-
<div className={
|
|
87
|
+
<div className={`control-slider gap-3 shadow-none ${className}`}>
|
|
98
88
|
{label && (
|
|
99
89
|
<label className="kol-helper-12 whitespace-nowrap shrink-0 w-fit" style={fontSize ? { fontSize } : undefined}>
|
|
100
90
|
{label}
|