This commit is contained in:
2026-05-07 16:50:25 +02:00
parent 0a2cbf05e5
commit 8415907bf1
8 changed files with 78292 additions and 310 deletions

View File

@@ -509,10 +509,10 @@ var GridLicenseManager = class extends BeanStub {
return this.licenseManager.getWatermarkMessage();
}
static setLicenseKey(licenseKey) {
LicenseManager.setLicenseKey(licenseKey);
}
static setChartsLicenseManager(chartsLicenseManager) {
LicenseManager.setChartsLicenseManager(chartsLicenseManager);
}
};

View File

@@ -7,12 +7,7 @@
"dependencies": {
"ag-grid-community": "^35.2.0",
"ag-grid-enterprise": "^35.2.0",
},
"devDependencies": {
"sigpro-ui": "^1.2.6",
},
"peerDependencies": {
"sigpro": "^1.2.28",
"sigpro": "git+http://gitea:3000/natxocc/sigpro",
},
},
},
@@ -31,8 +26,6 @@
"ag-grid-enterprise": ["ag-grid-enterprise@35.2.1", "", { "dependencies": { "ag-grid-community": "35.2.1" }, "optionalDependencies": { "ag-charts-community": "13.2.1", "ag-charts-enterprise": "13.2.1" } }, "sha512-nLl06cc7/THzf7mGZt7PotdeaBN74X3K9g2looyvJEymrOOJfjrLePrV4aNNhz/WZnATkbyblm5DM/qv3BeHKA=="],
"sigpro": ["sigpro@1.2.28", "", {}, "sha512-4fz70tNpLdgyreLweEuORdlTqvegCrjohgU6wHtil7+ItjSMsu2u0+1ICE06xsybgReCi+YCkGndwukwBLfMHA=="],
"sigpro-ui": ["sigpro-ui@1.2.6", "", {}, "sha512-I0HP4yGJ5wtVYTDd2Ig6Wqk7iUV8hlaq3DO7KZIG8ZKmZMRMWAaBzz5i4gFelY5hfpcwo0wJk7KVFYVbaXZXsg=="],
"sigpro": ["sigpro@git+http://gitea:3000/natxocc/sigpro#ab0e6e06974308b28cc54229cf0301ab81d7c132", {}, "ab0e6e06974308b28cc54229cf0301ab81d7c132"],
}
}

77737
dist/sigpro-grid.esm.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
const { h, watch, onUnmount } = window;
import { h, watch, onUnmount } from "sigpro"
import {
ModuleRegistry,
@@ -10,11 +10,14 @@ import {
TextEditorModule,
ClientSideRowModelModule,
themeQuartz,
iconSetQuartzLight,
createGrid
createGrid,
NumberFilterModule,
TextFilterModule,
DateFilterModule
} from "ag-grid-community";
import {
MultiFilterModule,
SetFilterModule,
CellSelectionModule,
PivotModule,
MasterDetailModule,
@@ -44,6 +47,10 @@ ModuleRegistry.registerModules([
StatusBarModule,
ExcelExportModule,
ClipboardModule,
NumberFilterModule,
TextFilterModule,
SetFilterModule,
DateFilterModule
]);
const Grid = (props) => {
@@ -55,9 +62,33 @@ const Grid = (props) => {
dark !== undefined
? (typeof dark === 'function' ? dark() : dark)
: document.documentElement.getAttribute('data-theme') === 'dark' ||
window.matchMedia('(prefers-color-scheme: dark)').matches;
window.matchMedia('(prefers-color-scheme: dark)').matches;
const getTheme = () => getDark() ? 'ag-theme-balham-dark' : 'ag-theme-balham';
const getTheme = () => {
const isDark = getDark();
if (isDark) {
return themeQuartz.withParams({
headerFontSize: 14,
headerVerticalPaddingScale: 0.4,
rowVerticalPaddingScale: 0.4,
backgroundColor: "#1d1d1d",
foregroundColor: "#ffffff",
headerBackgroundColor: "#2a2a2a",
headerForegroundColor: "#ffffff",
oddRowBackgroundColor: "#262626",
borderColor: "#404040",
browserColorScheme: "dark"
});
}
return themeQuartz.withParams({
browserColorScheme: "light",
headerFontSize: 14,
headerVerticalPaddingScale: 0.4,
rowVerticalPaddingScale: 0.4
});
};
const initGrid = (container) => {
if (cleanupFn) {
@@ -124,9 +155,10 @@ const Grid = (props) => {
const stopTheme = watch(() => {
if (!gridApi || gridApi.isDestroyed()) return;
getDark();
const currentTheme = getTheme();
if (currentTheme !== gridApi.getGridOption("theme")) {
gridApi.setGridOption("theme", currentTheme);
const newTheme = getTheme();
const currentTheme = gridApi.getGridOption("theme");
if (JSON.stringify(newTheme) !== JSON.stringify(currentTheme)) {
gridApi.setGridOption("theme", newTheme);
}
});
@@ -137,7 +169,7 @@ const Grid = (props) => {
Object.entries(newOptions).forEach(([key, val]) => {
try {
gridApi.setGridOption(key, val);
} catch (e) {}
} catch (e) { }
});
}
});
@@ -168,5 +200,4 @@ const Grid = (props) => {
});
};
if (typeof window !== 'undefined') window.Grid = Grid;
export { Grid, createGrid, themeQuartz, iconSetQuartzLight, ModuleRegistry };
export { Grid };

View File

@@ -14,11 +14,9 @@
],
"scripts": {
"clean": "rm -rf dist",
"build:iife": "bun build ./index.js --bundle --external sigpro-ui --outfile=./dist/sigpro-grid.js --format=iife --global-name=SigProGrid",
"build:iife:min": "bun build ./index.js --bundle --external sigpro-ui --outfile=./dist/sigpro-grid.min.js --format=iife --global-name=SigProGrid --minify",
"build:esm": "bun build ./index.js --bundle --external sigpro-ui --external ag-grid-community --external ag-grid-enterprise --outfile=./dist/sigpro-grid.esm.js --format=esm",
"build:esm:min": "bun build ./index.js --bundle --external sigpro-ui --external ag-grid-community --external ag-grid-enterprise --outfile=./dist/sigpro-grid.esm.min.js --format=esm --minify",
"build": "bun run clean && bun run build:iife:min && bun run build:esm:min",
"build:esm": "bun build ./index.js --bundle --external sigpro --outfile=./dist/sigpro-grid.esm.js --format=esm",
"build:esm:min": "bun build ./index.js --bundle --external sigpro --outfile=./dist/sigpro-grid.esm.min.js --format=esm --minify",
"build": "bun run clean && bun run build:esm && bun run build:esm:min",
"prepublishOnly": "npm run build"
},
"repository": {
@@ -39,12 +37,7 @@
"license": "MIT",
"dependencies": {
"ag-grid-community": "^35.2.0",
"ag-grid-enterprise": "^35.2.0"
},
"peerDependencies": {
"sigpro-ui": "^1.2.6"
},
"devDependencies": {
"sigpro-ui": "^1.2.6"
"ag-grid-enterprise": "^35.2.0",
"sigpro": "git+http://gitea:3000/natxocc/sigpro"
}
}

433
sigpro.js Normal file
View File

@@ -0,0 +1,433 @@
const isFunc = f => typeof f === "function"
const isObj = o => o && typeof o === "object"
const isArr = Array.isArray
const doc = typeof document !== "undefined" ? document : null
const ensureNode = n => n?._isRuntime ? n.container : (n instanceof Node ? n : doc.createTextNode(n == null ? "" : String(n)))
let activeEffect = null
let activeOwner = null
let isFlushing = false
let batchDepth = 0
const effectQueue = new Set()
const MOUNTED_NODES = new WeakMap()
const SVG_NS = "http://www.w3.org/2000/svg"
const XLINK_NS = "http://www.w3.org/1999/xlink"
const SVG_TAGS = new Set("svg,path,circle,rect,line,polyline,polygon,g,defs,text,textPath,tspan,use,symbol,image,marker,ellipse".split(","))
const dispose = eff => {
if (!eff || eff._disposed) return
eff._disposed = true
const stack = [eff]
while (stack.length) {
const e = stack.pop()
if (e._cleanups) {
e._cleanups.forEach(fn => fn())
e._cleanups.clear()
}
if (e._children) {
e._children.forEach(child => stack.push(child))
e._children.clear()
}
if (e._deps) {
e._deps.forEach(depSet => depSet.delete(e))
e._deps.clear()
}
}
}
const onUnmount = fn => {
if (activeOwner) (activeOwner._cleanups ||= new Set()).add(fn)
}
const untrack = fn => {
const p = activeEffect
activeEffect = null
try { return fn() } finally { activeEffect = p }
}
const createEffect = (fn, isComputed = false) => {
const effect = () => {
if (effect._disposed) return
if (effect._deps) effect._deps.forEach(s => s.delete(effect))
if (effect._cleanups) {
effect._cleanups.forEach(c => c())
effect._cleanups.clear()
}
const prevEffect = activeEffect
const prevOwner = activeOwner
activeEffect = activeOwner = effect
try {
return effect._result = fn()
} catch (e) {
console.error("[SigPro]", e)
} finally {
activeEffect = prevEffect
activeOwner = prevOwner
}
}
effect._deps = effect._cleanups = effect._children = null
effect._disposed = false
effect._isComputed = isComputed
effect._depth = activeEffect ? activeEffect._depth + 1 : 0
effect._mounts = []
effect._parent = activeOwner
if (activeOwner) (activeOwner._children ||= new Set()).add(effect)
return effect
}
const flush = () => {
if (isFlushing) return
isFlushing = true
const sorted = Array.from(effectQueue).sort((a, b) => a._depth - b._depth)
effectQueue.clear()
for (const e of sorted) if (!e._disposed) e()
isFlushing = false
}
const batch = fn => {
batchDepth++
try {
return fn()
} finally {
batchDepth--
if (batchDepth === 0 && effectQueue.size > 0 && !isFlushing) flush()
}
}
const trackUpdate = (subs, trigger = false) => {
if (!trigger && activeEffect && !activeEffect._disposed) {
subs.add(activeEffect);
(activeEffect._deps ||= new Set()).add(subs)
} else if (trigger && subs.size > 0) {
let hasQueue = false
for (const e of subs) {
if (e === activeEffect || e._disposed) continue
if (e._isComputed) {
e._dirty = true
if (e._subs) trackUpdate(e._subs, true)
} else {
effectQueue.add(e)
hasQueue = true
}
}
if (hasQueue && !isFlushing && batchDepth === 0) queueMicrotask(flush)
}
}
const $ = (val, key = null) => {
const subs = new Set()
if (isFunc(val)) {
let cache
const computed = () => {
if (computed._dirty) {
const prev = activeEffect
activeEffect = computed
try {
const next = val()
if (!Object.is(cache, next)) {
cache = next
trackUpdate(subs, true)
}
} finally {
activeEffect = prev
}
computed._dirty = false
}
trackUpdate(subs)
return cache
}
computed._isComputed = true
computed._subs = subs
computed._dirty = true
computed._deps = null
computed._disposed = false
return computed
}
if (key) try { val = JSON.parse(localStorage.getItem(key)) ?? val } catch (e) { }
return (...args) => {
if (args.length) {
const next = isFunc(args[0]) ? args[0](val) : args[0]
if (!Object.is(val, next)) {
val = next
if (key) localStorage.setItem(key, JSON.stringify(val))
trackUpdate(subs, true)
}
}
trackUpdate(subs)
return val
}
}
const watch = (sources, cb) => {
if (cb === undefined) {
const effect = createEffect(sources)
effect()
return () => dispose(effect)
}
const effect = createEffect(() => {
const vals = isArr(sources) ? sources.map(s => s()) : sources()
untrack(() => cb(vals))
})
effect()
return () => dispose(effect)
}
const cleanupNode = (node) => {
if (!node) return;
if (node._cleanups) {
node._cleanups.forEach(fn => fn());
node._cleanups.clear();
}
if (node._ownerEffect) dispose(node._ownerEffect);
if (node.childNodes) node.childNodes.forEach(n => cleanupNode(n));
};
var DANGEROUS_PROTOCOL = /^\s*(javascript|data|vbscript):/i;
var DANGEROUS_URI_ATTRS = new Set(["src", "href", "formaction", "action", "background", "code", "archive"]);
var isDangerousAttr = (key) => DANGEROUS_URI_ATTRS.has(key) || key.startsWith("on");
const validateAttr = (key, val) => {
if (val == null || val === false) return null
if (isDangerousAttr(key)) {
const sVal = String(val)
if (DANGEROUS_PROTOCOL.test(sVal)) return '#'
}
return val
}
const h = (tag, props = {}, children = []) => {
if (props instanceof Node || isArr(props) || !isObj(props)) {
children = props
props = {}
}
if (isFunc(tag)) {
const effect = createEffect(() => {
const result = tag(props, {
children,
emit: (ev, ...args) => props[`on${ev[0].toUpperCase()}${ev.slice(1)}`]?.(...args)
})
effect._result = result
return result
})
effect()
const result = effect._result
if (result == null) return null
const node = (result instanceof Node || (isArr(result) && result.every(n => n instanceof Node)))
? result
: doc.createTextNode(String(result))
const attach = n => {
if (isObj(n) && !n._isRuntime) {
n._mounts = effect._mounts || []
n._cleanups = effect._cleanups || new Set()
n._ownerEffect = effect
}
}
isArr(node) ? node.forEach(attach) : attach(node)
return node
}
const isSVG = SVG_TAGS.has(tag)
const el = isSVG ? doc.createElementNS(SVG_NS, tag) : doc.createElement(tag)
el._cleanups = new Set()
for (const k of Object.keys(props)) {
let v = props[k]
if (k === "ref") {
isFunc(v) ? v(el) : (v.current = el)
continue
}
if (isSVG && k.startsWith("xlink:")) {
const cleanVal = validateAttr(k.slice(6), v)
cleanVal == null
? el.removeAttributeNS(XLINK_NS, k.slice(6))
: el.setAttributeNS(XLINK_NS, k.slice(6), cleanVal)
continue
}
if (k.startsWith("on")) {
const ev = k.slice(2).toLowerCase()
el.addEventListener(ev, v)
const off = () => el.removeEventListener(ev, v)
el._cleanups.add(off)
onUnmount(off)
} else if (isFunc(v)) {
const effect = createEffect(() => {
const val = validateAttr(k, v())
if (k === "class") el.className = val || ""
else if (val == null) el.removeAttribute(k)
else if (k === "style" && typeof val === "string") el.setAttribute("style", val)
else if (k in el && !isSVG) el[k] = val
else el.setAttribute(k, val === true ? "" : val)
})
effect()
el._cleanups.add(() => dispose(effect))
onUnmount(() => dispose(effect))
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (k === "value" || k === "checked")) {
const evType = k === "checked" ? "change" : "input"
el.addEventListener(evType, ev => v(ev.target[k]))
}
} else {
const val = validateAttr(k, v)
if (val != null) {
if (k === "style" && typeof val === "string") el.setAttribute("style", val)
else if (k in el && !isSVG) el[k] = val
else el.setAttribute(k, val === true ? "" : val)
}
}
}
const append = c => {
if (isArr(c)) return c.forEach(append)
if (isFunc(c)) {
const anchor = doc.createTextNode("")
el.appendChild(anchor)
let currentNodes = []
const effect = createEffect(() => {
const res = c()
const next = (isArr(res) ? res : [res]).map(ensureNode)
currentNodes.forEach(n => {
if (n._isRuntime) n.destroy()
else cleanupNode(n)
if (n.parentNode) n.remove()
})
let ref = anchor
for (let i = next.length - 1; i >= 0; i--) {
const node = next[i]
if (node.parentNode !== ref.parentNode) ref.parentNode?.insertBefore(node, ref)
if (node._mounts) node._mounts.forEach(fn => fn())
ref = node
}
currentNodes = next
})
effect()
el._cleanups.add(() => dispose(effect))
onUnmount(() => dispose(effect))
} else {
const node = ensureNode(c)
el.appendChild(node)
if (node._mounts) node._mounts.forEach(fn => fn())
}
}
append(children)
return el
}
const render = renderFn => {
const cleanups = new Set()
const previousOwner = activeOwner
const previousEffect = activeEffect
const container = doc.createElement("div")
container.style.display = "contents"
container.setAttribute("role", "presentation")
activeOwner = { _cleanups: cleanups }
activeEffect = null
const processResult = result => {
if (!result) return
if (result._isRuntime) {
cleanups.add(result.destroy)
container.appendChild(result.container)
} else if (isArr(result)) {
result.forEach(processResult)
} else {
container.appendChild(result instanceof Node ? result : doc.createTextNode(String(result == null ? "" : result)))
}
}
try {
processResult(renderFn({ onCleanup: fn => cleanups.add(fn) }))
} finally {
activeOwner = previousOwner
activeEffect = previousEffect
}
return {
_isRuntime: true,
container,
destroy: () => {
cleanups.forEach(fn => fn())
cleanupNode(container)
container.remove()
}
}
}
const when = (cond, SIP, NOP = null) => {
const anchor = doc.createTextNode("")
const root = h("div", { style: "display:contents" }, [anchor])
let currentView = null
watch(
() => !!(isFunc(cond) ? cond() : cond),
show => {
if (currentView) {
currentView.destroy()
currentView = null
}
const content = show ? SIP : NOP
if (content) {
currentView = render(() => isFunc(content) ? content() : content)
root.insertBefore(currentView.container, anchor)
}
}
)
onUnmount(() => currentView?.destroy())
return root
}
const each = (src, itemFn, keyField) => {
const anchor = doc.createTextNode("")
const root = h("div", { style: "display:contents" }, [anchor])
let cache = new Map()
watch(() => (isFunc(src) ? src() : src) || [], items => {
const nextCache = new Map()
const nextOrder = []
const newItems = items || []
for (let i = 0; i < newItems.length; i++) {
const item = newItems[i]
const key = keyField ? (item?.[keyField] ?? i) : (item?.id ?? i)
let view = cache.get(key)
if (!view) view = render(() => itemFn(item, i))
else cache.delete(key)
nextCache.set(key, view)
nextOrder.push(view)
}
cache.forEach(view => view.destroy())
let lastRef = anchor
for (let i = nextOrder.length - 1; i >= 0; i--) {
const view = nextOrder[i]
const node = view.container
if (node.nextSibling !== lastRef) root.insertBefore(node, lastRef)
lastRef = node
}
cache = nextCache
})
return root
}
const Fragment = (props) => props.children;
const mount = (comp, target) => {
const t = typeof target === "string" ? doc.querySelector(target) : target
if (!t) return
if (MOUNTED_NODES.has(t)) MOUNTED_NODES.get(t).destroy()
const inst = render(isFunc(comp) ? comp : () => comp)
t.replaceChildren(inst.container)
MOUNTED_NODES.set(t, inst)
return inst
}
if (typeof window !== "undefined") {
"a abbr article aside audio b blockquote br button canvas caption cite code col colgroup datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hr i iframe img input ins kbd label legend li main mark meter nav object ol optgroup option output p picture pre progress section select slot small source span strong sub summary sup svg table tbody td template textarea tfoot th thead time tr u ul video"
.split(" ")
.forEach(tag => { window[tag] = (props, children) => h(tag, props, children) })
}
export { $, watch, batch, h, Fragment, render, mount, when, each, onUnmount, isArr, isFunc, isObj }