@kolkrabbi/kol-component 0.26.1 → 0.27.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.26.1",
3
+ "version": "0.27.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",
@@ -1,25 +1,27 @@
1
1
  import { useState } from 'react'
2
+ import { Icon } from '@kolkrabbi/kol-icons'
2
3
 
3
4
  /**
4
- * CopyButton — copy-to-clipboard chip. Clipboard icon + Copy/Copied label
5
- * swap with a 1.8s reset; silent when the clipboard is blocked. Chrome
6
- * comes from .kol-copy-btn (kol-theme); parents add their own positioning
7
- * class (e.g. CodeBlock's .kol-codeblock-copy).
5
+ * CopyButton — THE copy-to-clipboard control (2026-08-09 user ruling): the
6
+ * 32×32 icon button `copy` glyph flipping to `check` for 2s on copied,
7
+ * no text label. This is the button CodeBlock carried privately since the
8
+ * 2026-07-28 elder replication, promoted to the one shared atom; the old
9
+ * Copy/Copied label chip (one-off SVGs outside the icon set) is retired.
10
+ * Chrome comes from .kol-copy-btn (kol-theme); parents add their own
11
+ * positioning class (e.g. CodeBlock's .kol-codeblock-copy).
8
12
  *
9
13
  * Props:
10
14
  * text — string (or () => string) written to the clipboard
11
- * label — show the Copy/Copied text next to the icon (default true;
12
- * false = icon-only for tight spots)
13
15
  * className — extra classes (positioning etc.)
14
16
  */
15
- export default function CopyButton({ text, label = true, className = '', ...props }) {
17
+ export default function CopyButton({ text, className = '', ...props }) {
16
18
  const [copied, setCopied] = useState(false)
17
19
 
18
20
  const onCopy = async () => {
19
21
  try {
20
22
  await navigator.clipboard.writeText(typeof text === 'function' ? text() : String(text ?? ''))
21
23
  setCopied(true)
22
- setTimeout(() => setCopied(false), 1800)
24
+ setTimeout(() => setCopied(false), 2000)
23
25
  } catch {
24
26
  /* clipboard blocked — silent */
25
27
  }
@@ -34,17 +36,7 @@ export default function CopyButton({ text, label = true, className = '', ...prop
34
36
  title={copied ? 'Copied' : 'Copy'}
35
37
  {...props}
36
38
  >
37
- {copied ? (
38
- <svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true">
39
- <path d="M5 10 L9 14 L15 6" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
40
- </svg>
41
- ) : (
42
- <svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true">
43
- <rect x="6" y="3" width="10" height="12" rx="1" fill="none" stroke="currentColor" strokeWidth="1.4" />
44
- <rect x="4" y="6" width="10" height="12" rx="1" fill="none" stroke="currentColor" strokeWidth="1.4" />
45
- </svg>
46
- )}
47
- {label && <span>{copied ? 'Copied' : 'Copy'}</span>}
39
+ <Icon name={copied ? 'check' : 'copy'} size={16} />
48
40
  </button>
49
41
  )
50
42
  }
@@ -1,15 +1,14 @@
1
- import { useState } from 'react'
2
1
  import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
3
2
  import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
4
- import { Icon } from '@kolkrabbi/kol-icons'
3
+ import CopyButton from '../atoms/CopyButton.jsx'
5
4
 
6
5
  /**
7
6
  * CodeBlock — REPLICATED from the elder reference
8
7
  * (kol-website/packages/ui/src/molecules/CodeBlock.jsx, 2026-07-28 user
9
8
  * mandate): react-syntax-highlighter (Prism) with the oneDark theme flattened
10
9
  * onto KOL chrome — transparent bg, 14px/1.6 mono, no text-shadow — a single
11
- * filename-or-language chip, and a 32×32 icon copy button (`copy` glyph →
12
- * check on copied). Chrome lives in kol-theme (kol-components-molecules.css).
10
+ * filename-or-language chip, and the CopyButton atom positioned in-frame
11
+ * (.kol-codeblock-copy). Chrome lives in kol-theme (kol-components-molecules.css).
13
12
  *
14
13
  * Input shapes (first match wins per field):
15
14
  * • Portable Text: `value={{ code, language, filename }}`
@@ -25,12 +24,6 @@ import { Icon } from '@kolkrabbi/kol-icons'
25
24
  * @param {boolean} [bare] drop the FRAME; the host owns it. Not a size.
26
25
  */
27
26
 
28
- const CheckMarkIcon = () => (
29
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
30
- <path d="M19.4697 6.41987C19.7626 6.12697 20.2373 6.12697 20.5302 6.41987C20.8231 6.71276 20.8231 7.18752 20.5302 7.48041L10.9443 17.0663C9.87038 18.1401 8.12951 18.1401 7.05561 17.0663L3.46967 13.4804C3.17678 13.1875 3.17678 12.7128 3.46967 12.4199C3.76256 12.127 4.23732 12.127 4.53022 12.4199L8.11615 16.0058C8.60427 16.4938 9.39561 16.4938 9.88373 16.0058L19.4697 6.41987Z" fill="currentColor"/>
31
- </svg>
32
- )
33
-
34
27
  const syntaxTheme = (foregroundToken = 80) => ({
35
28
  ...oneDark,
36
29
  'pre[class*="language-"]': {
@@ -76,22 +69,10 @@ const syntaxTheme = (foregroundToken = 80) => ({
76
69
  * on both axes. Size is INDEPENDENT of `bare`: bare removes the frame, size
77
70
  * sets the box, and a bare block still has one. */
78
71
  export default function CodeBlock({ children, code: codeProp, language: languageProp, filename: filenameProp, value, bare = false, size = 'md' }) {
79
- const [copied, setCopied] = useState(false)
80
-
81
72
  const code = String(value?.code ?? codeProp ?? children ?? '')
82
73
  const language = value?.language ?? languageProp ?? 'text'
83
74
  const filename = value?.filename ?? filenameProp
84
75
 
85
- const handleCopy = async () => {
86
- try {
87
- await navigator.clipboard.writeText(code)
88
- setCopied(true)
89
- setTimeout(() => setCopied(false), 2000)
90
- } catch {
91
- /* clipboard blocked — silent */
92
- }
93
- }
94
-
95
76
  return (
96
77
  <div className={bare ? '' : 'kol-codeblock-wrapper'}>
97
78
  <div className={`kol-codeblock kol-codeblock--${size}${bare ? ' kol-codeblock--bare' : ''}`}>
@@ -124,15 +105,7 @@ export default function CodeBlock({ children, code: codeProp, language: language
124
105
  >
125
106
  {code}
126
107
  </SyntaxHighlighter>
127
- <button
128
- type="button"
129
- className="kol-codeblock-copy"
130
- onClick={handleCopy}
131
- aria-label={copied ? 'Code copied!' : 'Copy code'}
132
- title={copied ? 'Code copied!' : 'Copy code'}
133
- >
134
- {copied ? <CheckMarkIcon /> : <Icon name="copy" size={16} />}
135
- </button>
108
+ <CopyButton text={code} className="kol-codeblock-copy" />
136
109
  </div>
137
110
  </div>
138
111
  )