@uniweb/scholar 0.2.0 → 0.2.2

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.
@@ -1,228 +0,0 @@
1
- /**
2
- * Date Formatting Utilities
3
- *
4
- * Functions for formatting dates in various citation styles.
5
- *
6
- * @module @uniweb/scholar/bibliography/utils/dates
7
- */
8
-
9
- /**
10
- * Month names for formatting
11
- */
12
- const MONTHS_FULL = [
13
- 'January',
14
- 'February',
15
- 'March',
16
- 'April',
17
- 'May',
18
- 'June',
19
- 'July',
20
- 'August',
21
- 'September',
22
- 'October',
23
- 'November',
24
- 'December',
25
- ]
26
-
27
- const MONTHS_SHORT = [
28
- 'Jan.',
29
- 'Feb.',
30
- 'Mar.',
31
- 'Apr.',
32
- 'May',
33
- 'June',
34
- 'July',
35
- 'Aug.',
36
- 'Sep.',
37
- 'Oct.',
38
- 'Nov.',
39
- 'Dec.',
40
- ]
41
-
42
- /**
43
- * Parse a date from various formats
44
- *
45
- * @param {string|number|Date|Object} date - Date input
46
- * @returns {{ year?: number, month?: number, day?: number }}
47
- */
48
- export function parseDate(date) {
49
- if (!date) return {}
50
-
51
- // Already structured
52
- if (typeof date === 'object' && !(date instanceof Date)) {
53
- return {
54
- year: date.year ?? date.Year,
55
- month: date.month ?? date.Month,
56
- day: date.day ?? date.Day,
57
- }
58
- }
59
-
60
- // JavaScript Date
61
- if (date instanceof Date) {
62
- return {
63
- year: date.getFullYear(),
64
- month: date.getMonth() + 1,
65
- day: date.getDate(),
66
- }
67
- }
68
-
69
- // Number (year only)
70
- if (typeof date === 'number') {
71
- return { year: date }
72
- }
73
-
74
- // String parsing
75
- const str = String(date).trim()
76
-
77
- // ISO format: YYYY-MM-DD
78
- const isoMatch = str.match(/^(\d{4})(?:-(\d{1,2})(?:-(\d{1,2}))?)?/)
79
- if (isoMatch) {
80
- return {
81
- year: parseInt(isoMatch[1], 10),
82
- month: isoMatch[2] ? parseInt(isoMatch[2], 10) : undefined,
83
- day: isoMatch[3] ? parseInt(isoMatch[3], 10) : undefined,
84
- }
85
- }
86
-
87
- // Year only
88
- const yearMatch = str.match(/^\d{4}$/)
89
- if (yearMatch) {
90
- return { year: parseInt(str, 10) }
91
- }
92
-
93
- // Month Year: "January 2024", "Jan 2024"
94
- const monthYearMatch = str.match(
95
- /^(\w+)\s+(\d{4})$/
96
- )
97
- if (monthYearMatch) {
98
- const monthName = monthYearMatch[1].toLowerCase()
99
- const monthIndex = MONTHS_FULL.findIndex(
100
- (m) => m.toLowerCase().startsWith(monthName.slice(0, 3))
101
- )
102
- return {
103
- year: parseInt(monthYearMatch[2], 10),
104
- month: monthIndex !== -1 ? monthIndex + 1 : undefined,
105
- }
106
- }
107
-
108
- return {}
109
- }
110
-
111
- /**
112
- * Format date for APA style
113
- *
114
- * @param {Object} date - Parsed date object
115
- * @returns {string}
116
- */
117
- export function formatApaDate(date) {
118
- const parsed = parseDate(date)
119
-
120
- if (!parsed.year) return 'n.d.'
121
-
122
- if (parsed.month && parsed.day) {
123
- return `${parsed.year}, ${MONTHS_FULL[parsed.month - 1]} ${parsed.day}`
124
- }
125
-
126
- if (parsed.month) {
127
- return `${parsed.year}, ${MONTHS_FULL[parsed.month - 1]}`
128
- }
129
-
130
- return String(parsed.year)
131
- }
132
-
133
- /**
134
- * Format date for MLA style
135
- *
136
- * @param {Object} date - Parsed date object
137
- * @returns {string}
138
- */
139
- export function formatMlaDate(date) {
140
- const parsed = parseDate(date)
141
-
142
- if (!parsed.year) return ''
143
-
144
- if (parsed.month && parsed.day) {
145
- return `${parsed.day} ${MONTHS_SHORT[parsed.month - 1]} ${parsed.year}`
146
- }
147
-
148
- if (parsed.month) {
149
- return `${MONTHS_SHORT[parsed.month - 1]} ${parsed.year}`
150
- }
151
-
152
- return String(parsed.year)
153
- }
154
-
155
- /**
156
- * Format date for Chicago style
157
- *
158
- * @param {Object} date - Parsed date object
159
- * @returns {string}
160
- */
161
- export function formatChicagoDate(date) {
162
- const parsed = parseDate(date)
163
-
164
- if (!parsed.year) return 'n.d.'
165
-
166
- if (parsed.month && parsed.day) {
167
- return `${MONTHS_FULL[parsed.month - 1]} ${parsed.day}, ${parsed.year}`
168
- }
169
-
170
- if (parsed.month) {
171
- return `${MONTHS_FULL[parsed.month - 1]} ${parsed.year}`
172
- }
173
-
174
- return String(parsed.year)
175
- }
176
-
177
- /**
178
- * Format date for IEEE style
179
- *
180
- * @param {Object} date - Parsed date object
181
- * @returns {string}
182
- */
183
- export function formatIeeeDate(date) {
184
- const parsed = parseDate(date)
185
-
186
- if (!parsed.year) return ''
187
-
188
- if (parsed.month) {
189
- return `${MONTHS_SHORT[parsed.month - 1]} ${parsed.year}`
190
- }
191
-
192
- return String(parsed.year)
193
- }
194
-
195
- /**
196
- * Format date for a specific style
197
- *
198
- * @param {any} date - Date input
199
- * @param {Object} [options]
200
- * @param {string} [options.style='apa'] - Citation style
201
- * @returns {string}
202
- */
203
- export function formatDate(date, options = {}) {
204
- const { style = 'apa' } = options
205
-
206
- switch (style) {
207
- case 'apa':
208
- return formatApaDate(date)
209
- case 'mla':
210
- return formatMlaDate(date)
211
- case 'chicago':
212
- return formatChicagoDate(date)
213
- case 'ieee':
214
- return formatIeeeDate(date)
215
- default:
216
- return formatApaDate(date)
217
- }
218
- }
219
-
220
- /**
221
- * Get year from date
222
- *
223
- * @param {any} date - Date input
224
- * @returns {number|undefined}
225
- */
226
- export function getYear(date) {
227
- return parseDate(date).year
228
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Bibliography Utilities
3
- *
4
- * @module @uniweb/scholar/bibliography/utils
5
- */
6
-
7
- export * from './authors.js'
8
- export * from './dates.js'
package/src/math/Math.jsx DELETED
@@ -1,115 +0,0 @@
1
- /**
2
- * Math Component
3
- *
4
- * Renders LaTeX math expressions using KaTeX.
5
- * Supports both inline and display (block) modes.
6
- *
7
- * @module @uniweb/scholar/math/Math
8
- */
9
-
10
- import React, { useEffect, useState } from 'react'
11
- import { loadKatex } from './katex-loader.js'
12
-
13
- /**
14
- * Math - Render LaTeX math expressions
15
- *
16
- * @param {Object} props
17
- * @param {string} props.children - LaTeX expression to render
18
- * @param {boolean} [props.display=false] - Display mode (block) vs inline
19
- * @param {string} [props.className] - Additional CSS classes
20
- *
21
- * @example
22
- * // Inline math
23
- * <Math>E = mc^2</Math>
24
- *
25
- * @example
26
- * // Display (block) math
27
- * <Math display>
28
- * \int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
29
- * </Math>
30
- */
31
- export function Math({ children, display = false, className, ...props }) {
32
- const [html, setHtml] = useState(null)
33
- const [error, setError] = useState(null)
34
-
35
- // Extract LaTeX string from children
36
- const latex = typeof children === 'string' ? children.trim() : ''
37
-
38
- useEffect(() => {
39
- if (!latex) return
40
-
41
- let cancelled = false
42
-
43
- async function render() {
44
- const katex = await loadKatex()
45
- if (cancelled || !katex) return
46
-
47
- try {
48
- const rendered = katex.renderToString(latex, {
49
- displayMode: display,
50
- throwOnError: false,
51
- errorColor: '#cc0000',
52
- })
53
- if (!cancelled) {
54
- setHtml(rendered)
55
- setError(null)
56
- }
57
- } catch (e) {
58
- if (!cancelled) {
59
- setError(e.message)
60
- setHtml(null)
61
- }
62
- }
63
- }
64
-
65
- render()
66
-
67
- return () => {
68
- cancelled = true
69
- }
70
- }, [latex, display])
71
-
72
- // Error state
73
- if (error) {
74
- return (
75
- <span
76
- className={className}
77
- style={{ color: '#cc0000', fontFamily: 'monospace' }}
78
- title={error}
79
- {...props}
80
- >
81
- {latex}
82
- </span>
83
- )
84
- }
85
-
86
- // Loading state - show raw LaTeX in code format
87
- if (!html) {
88
- return (
89
- <code className={className} {...props}>
90
- {latex}
91
- </code>
92
- )
93
- }
94
-
95
- // Rendered math
96
- if (display) {
97
- return (
98
- <div
99
- className={className}
100
- dangerouslySetInnerHTML={{ __html: html }}
101
- {...props}
102
- />
103
- )
104
- }
105
-
106
- return (
107
- <span
108
- className={className}
109
- dangerouslySetInnerHTML={{ __html: html }}
110
- {...props}
111
- />
112
- )
113
- }
114
-
115
- export default Math
@@ -1,105 +0,0 @@
1
- /**
2
- * KaTeX Lazy Loader
3
- *
4
- * Provides lazy loading of KaTeX with module-level caching.
5
- * KaTeX is only loaded when math rendering is actually needed.
6
- *
7
- * @module @uniweb/scholar/math/katex-loader
8
- */
9
-
10
- // Module-level state for singleton pattern
11
- let katexInstance = null
12
- let katexLoadPromise = null
13
- let cssInjected = false
14
-
15
- /**
16
- * CDN URL for KaTeX CSS (matches the katex version in package.json)
17
- */
18
- const KATEX_CSS_URL = 'https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css'
19
-
20
- /**
21
- * Inject KaTeX CSS into the document head
22
- * Only injects once per page load
23
- */
24
- function injectKatexCSS() {
25
- if (cssInjected || typeof document === 'undefined') return
26
-
27
- const styleId = 'uniweb-katex-css'
28
-
29
- // Check if already injected
30
- if (document.getElementById(styleId)) {
31
- cssInjected = true
32
- return
33
- }
34
-
35
- const link = document.createElement('link')
36
- link.id = styleId
37
- link.rel = 'stylesheet'
38
- link.href = KATEX_CSS_URL
39
- link.crossOrigin = 'anonymous'
40
- document.head.appendChild(link)
41
-
42
- cssInjected = true
43
- }
44
-
45
- /**
46
- * Load KaTeX lazily
47
- *
48
- * Returns cached instance if already loaded, otherwise loads
49
- * KaTeX dynamically and injects its CSS.
50
- *
51
- * @returns {Promise<Object>} The KaTeX module
52
- */
53
- export async function loadKatex() {
54
- if (katexInstance) return katexInstance
55
- if (katexLoadPromise) return katexLoadPromise
56
-
57
- katexLoadPromise = (async () => {
58
- try {
59
- const katex = await import('katex')
60
- katexInstance = katex.default || katex
61
-
62
- // Inject CSS when KaTeX is loaded
63
- injectKatexCSS()
64
-
65
- return katexInstance
66
- } catch (error) {
67
- console.warn('[scholar/math] Failed to load KaTeX:', error)
68
- katexLoadPromise = null
69
- return null
70
- }
71
- })()
72
-
73
- return katexLoadPromise
74
- }
75
-
76
- /**
77
- * Check if KaTeX is already loaded
78
- *
79
- * @returns {boolean} True if KaTeX is loaded and ready
80
- */
81
- export function isKatexLoaded() {
82
- return katexInstance !== null
83
- }
84
-
85
- /**
86
- * Render LaTeX to HTML string
87
- *
88
- * @param {string} latex - LaTeX string to render
89
- * @param {Object} options - KaTeX options
90
- * @returns {Promise<string|null>} Rendered HTML or null on error
91
- */
92
- export async function renderLatex(latex, options = {}) {
93
- const katex = await loadKatex()
94
- if (!katex) return null
95
-
96
- try {
97
- return katex.renderToString(latex, {
98
- throwOnError: false,
99
- ...options,
100
- })
101
- } catch (error) {
102
- console.warn('[scholar/math] LaTeX render error:', error.message)
103
- return null
104
- }
105
- }