New docs
This commit is contained in:
275
src/docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
275
src/docs/.vitepress/cache/deps/@theme_index.js
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
import {
|
||||
useMediaQuery
|
||||
} from "./chunk-RLEUDPPB.js";
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
shallowRef,
|
||||
watch
|
||||
} from "./chunk-3S55Y3P7.js";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/index.js
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/base.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
|
||||
import "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
|
||||
import VPBadge from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
||||
import Layout from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/Layout.vue";
|
||||
import { default as default2 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
||||
import { default as default3 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
|
||||
import { default as default4 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
|
||||
import { default as default5 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
|
||||
import { default as default6 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
|
||||
import { default as default7 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
|
||||
import { default as default8 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
|
||||
import { default as default9 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
|
||||
import { default as default10 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
|
||||
import { default as default11 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
|
||||
import { default as default12 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
|
||||
import { default as default13 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
|
||||
import { default as default14 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
|
||||
import { default as default15 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
|
||||
import { default as default16 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
|
||||
import { default as default17 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
|
||||
import { default as default18 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
|
||||
import { default as default19 } from "/config/workspace/sigpro/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
|
||||
import { onContentUpdated } from "vitepress";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/outline.js
|
||||
import { getScrollOffset } from "vitepress";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/support/utils.js
|
||||
import { withBase } from "vitepress";
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/data.js
|
||||
import { useData as useData$ } from "vitepress";
|
||||
var useData = useData$;
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/support/utils.js
|
||||
function ensureStartingSlash(path) {
|
||||
return path.startsWith("/") ? path : `/${path}`;
|
||||
}
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/support/sidebar.js
|
||||
function getSidebar(_sidebar, path) {
|
||||
if (Array.isArray(_sidebar))
|
||||
return addBase(_sidebar);
|
||||
if (_sidebar == null)
|
||||
return [];
|
||||
path = ensureStartingSlash(path);
|
||||
const dir = Object.keys(_sidebar).sort((a, b) => {
|
||||
return b.split("/").length - a.split("/").length;
|
||||
}).find((dir2) => {
|
||||
return path.startsWith(ensureStartingSlash(dir2));
|
||||
});
|
||||
const sidebar = dir ? _sidebar[dir] : [];
|
||||
return Array.isArray(sidebar) ? addBase(sidebar) : addBase(sidebar.items, sidebar.base);
|
||||
}
|
||||
function getSidebarGroups(sidebar) {
|
||||
const groups = [];
|
||||
let lastGroupIndex = 0;
|
||||
for (const index in sidebar) {
|
||||
const item = sidebar[index];
|
||||
if (item.items) {
|
||||
lastGroupIndex = groups.push(item);
|
||||
continue;
|
||||
}
|
||||
if (!groups[lastGroupIndex]) {
|
||||
groups.push({ items: [] });
|
||||
}
|
||||
groups[lastGroupIndex].items.push(item);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
function addBase(items, _base) {
|
||||
return [...items].map((_item) => {
|
||||
const item = { ..._item };
|
||||
const base = item.base || _base;
|
||||
if (base && item.link)
|
||||
item.link = base + item.link;
|
||||
if (item.items)
|
||||
item.items = addBase(item.items, base);
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/sidebar.js
|
||||
function useSidebar() {
|
||||
const { frontmatter, page, theme: theme2 } = useData();
|
||||
const is960 = useMediaQuery("(min-width: 960px)");
|
||||
const isOpen = ref(false);
|
||||
const _sidebar = computed(() => {
|
||||
const sidebarConfig = theme2.value.sidebar;
|
||||
const relativePath = page.value.relativePath;
|
||||
return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : [];
|
||||
});
|
||||
const sidebar = ref(_sidebar.value);
|
||||
watch(_sidebar, (next, prev) => {
|
||||
if (JSON.stringify(next) !== JSON.stringify(prev))
|
||||
sidebar.value = _sidebar.value;
|
||||
});
|
||||
const hasSidebar = computed(() => {
|
||||
return frontmatter.value.sidebar !== false && sidebar.value.length > 0 && frontmatter.value.layout !== "home";
|
||||
});
|
||||
const leftAside = computed(() => {
|
||||
if (hasAside)
|
||||
return frontmatter.value.aside == null ? theme2.value.aside === "left" : frontmatter.value.aside === "left";
|
||||
return false;
|
||||
});
|
||||
const hasAside = computed(() => {
|
||||
if (frontmatter.value.layout === "home")
|
||||
return false;
|
||||
if (frontmatter.value.aside != null)
|
||||
return !!frontmatter.value.aside;
|
||||
return theme2.value.aside !== false;
|
||||
});
|
||||
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value);
|
||||
const sidebarGroups = computed(() => {
|
||||
return hasSidebar.value ? getSidebarGroups(sidebar.value) : [];
|
||||
});
|
||||
function open() {
|
||||
isOpen.value = true;
|
||||
}
|
||||
function close() {
|
||||
isOpen.value = false;
|
||||
}
|
||||
function toggle() {
|
||||
isOpen.value ? close() : open();
|
||||
}
|
||||
return {
|
||||
isOpen,
|
||||
sidebar,
|
||||
sidebarGroups,
|
||||
hasSidebar,
|
||||
hasAside,
|
||||
leftAside,
|
||||
isSidebarEnabled,
|
||||
open,
|
||||
close,
|
||||
toggle
|
||||
};
|
||||
}
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/outline.js
|
||||
var ignoreRE = /\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/;
|
||||
var resolvedHeaders = [];
|
||||
function getHeaders(range) {
|
||||
const headers = [
|
||||
...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")
|
||||
].filter((el) => el.id && el.hasChildNodes()).map((el) => {
|
||||
const level = Number(el.tagName[1]);
|
||||
return {
|
||||
element: el,
|
||||
title: serializeHeader(el),
|
||||
link: "#" + el.id,
|
||||
level
|
||||
};
|
||||
});
|
||||
return resolveHeaders(headers, range);
|
||||
}
|
||||
function serializeHeader(h) {
|
||||
let ret = "";
|
||||
for (const node of h.childNodes) {
|
||||
if (node.nodeType === 1) {
|
||||
if (ignoreRE.test(node.className))
|
||||
continue;
|
||||
ret += node.textContent;
|
||||
} else if (node.nodeType === 3) {
|
||||
ret += node.textContent;
|
||||
}
|
||||
}
|
||||
return ret.trim();
|
||||
}
|
||||
function resolveHeaders(headers, range) {
|
||||
if (range === false) {
|
||||
return [];
|
||||
}
|
||||
const levelsRange = (typeof range === "object" && !Array.isArray(range) ? range.level : range) || 2;
|
||||
const [high, low] = typeof levelsRange === "number" ? [levelsRange, levelsRange] : levelsRange === "deep" ? [2, 6] : levelsRange;
|
||||
return buildTree(headers, high, low);
|
||||
}
|
||||
function buildTree(data, min, max) {
|
||||
resolvedHeaders.length = 0;
|
||||
const result = [];
|
||||
const stack = [];
|
||||
data.forEach((item) => {
|
||||
const node = { ...item, children: [] };
|
||||
let parent = stack[stack.length - 1];
|
||||
while (parent && parent.level >= node.level) {
|
||||
stack.pop();
|
||||
parent = stack[stack.length - 1];
|
||||
}
|
||||
if (node.element.classList.contains("ignore-header") || parent && "shouldIgnore" in parent) {
|
||||
stack.push({ level: node.level, shouldIgnore: true });
|
||||
return;
|
||||
}
|
||||
if (node.level > max || node.level < min)
|
||||
return;
|
||||
resolvedHeaders.push({ element: node.element, link: node.link });
|
||||
if (parent)
|
||||
parent.children.push(node);
|
||||
else
|
||||
result.push(node);
|
||||
stack.push(node);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
|
||||
function useLocalNav() {
|
||||
const { theme: theme2, frontmatter } = useData();
|
||||
const headers = shallowRef([]);
|
||||
const hasLocalNav = computed(() => {
|
||||
return headers.value.length > 0;
|
||||
});
|
||||
onContentUpdated(() => {
|
||||
headers.value = getHeaders(frontmatter.value.outline ?? theme2.value.outline);
|
||||
});
|
||||
return {
|
||||
headers,
|
||||
hasLocalNav
|
||||
};
|
||||
}
|
||||
|
||||
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
|
||||
var theme = {
|
||||
Layout,
|
||||
enhanceApp: ({ app }) => {
|
||||
app.component("Badge", VPBadge);
|
||||
}
|
||||
};
|
||||
var without_fonts_default = theme;
|
||||
export {
|
||||
default2 as VPBadge,
|
||||
default3 as VPButton,
|
||||
default4 as VPDocAsideSponsors,
|
||||
default5 as VPFeatures,
|
||||
default6 as VPHomeContent,
|
||||
default7 as VPHomeFeatures,
|
||||
default8 as VPHomeHero,
|
||||
default9 as VPHomeSponsors,
|
||||
default10 as VPImage,
|
||||
default11 as VPLink,
|
||||
default12 as VPNavBarSearch,
|
||||
default13 as VPSocialLink,
|
||||
default14 as VPSocialLinks,
|
||||
default15 as VPSponsors,
|
||||
default16 as VPTeamMembers,
|
||||
default17 as VPTeamPage,
|
||||
default18 as VPTeamPageSection,
|
||||
default19 as VPTeamPageTitle,
|
||||
without_fonts_default as default,
|
||||
useLocalNav,
|
||||
useSidebar
|
||||
};
|
||||
//# sourceMappingURL=@theme_index.js.map
|
||||
7
src/docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/@theme_index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
40
src/docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
40
src/docs/.vitepress/cache/deps/_metadata.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"hash": "0412844f",
|
||||
"configHash": "5a0057cf",
|
||||
"lockfileHash": "e3b0c442",
|
||||
"browserHash": "d3515516",
|
||||
"optimized": {
|
||||
"vue": {
|
||||
"src": "../../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
||||
"file": "vue.js",
|
||||
"fileHash": "5e2bcecf",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vue/devtools-api": {
|
||||
"src": "../../../../../node_modules/@vue/devtools-api/dist/index.js",
|
||||
"file": "vitepress___@vue_devtools-api.js",
|
||||
"fileHash": "604942f7",
|
||||
"needsInterop": false
|
||||
},
|
||||
"vitepress > @vueuse/core": {
|
||||
"src": "../../../../../node_modules/@vueuse/core/index.mjs",
|
||||
"file": "vitepress___@vueuse_core.js",
|
||||
"fileHash": "f08e5a15",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@theme/index": {
|
||||
"src": "../../../../../node_modules/vitepress/dist/client/theme-default/index.js",
|
||||
"file": "@theme_index.js",
|
||||
"fileHash": "442c9e5b",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"chunk-RLEUDPPB": {
|
||||
"file": "chunk-RLEUDPPB.js"
|
||||
},
|
||||
"chunk-3S55Y3P7": {
|
||||
"file": "chunk-3S55Y3P7.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
12951
src/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js
vendored
Normal file
12951
src/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
src/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/chunk-3S55Y3P7.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
9719
src/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js
vendored
Normal file
9719
src/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
src/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/chunk-RLEUDPPB.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
3
src/docs/.vitepress/cache/deps/package.json
vendored
Normal file
3
src/docs/.vitepress/cache/deps/package.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
4505
src/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
4505
src/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
src/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
583
src/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
583
src/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
import {
|
||||
DefaultMagicKeysAliasMap,
|
||||
StorageSerializers,
|
||||
TransitionPresets,
|
||||
assert,
|
||||
breakpointsAntDesign,
|
||||
breakpointsBootstrapV5,
|
||||
breakpointsElement,
|
||||
breakpointsMasterCss,
|
||||
breakpointsPrimeFlex,
|
||||
breakpointsQuasar,
|
||||
breakpointsSematic,
|
||||
breakpointsTailwind,
|
||||
breakpointsVuetify,
|
||||
breakpointsVuetifyV2,
|
||||
breakpointsVuetifyV3,
|
||||
bypassFilter,
|
||||
camelize,
|
||||
clamp,
|
||||
cloneFnJSON,
|
||||
computedAsync,
|
||||
computedEager,
|
||||
computedInject,
|
||||
computedWithControl,
|
||||
containsProp,
|
||||
controlledRef,
|
||||
createEventHook,
|
||||
createFetch,
|
||||
createFilterWrapper,
|
||||
createGlobalState,
|
||||
createInjectionState,
|
||||
createRef,
|
||||
createReusableTemplate,
|
||||
createSharedComposable,
|
||||
createSingletonPromise,
|
||||
createTemplatePromise,
|
||||
createUnrefFn,
|
||||
customStorageEventName,
|
||||
debounceFilter,
|
||||
defaultDocument,
|
||||
defaultLocation,
|
||||
defaultNavigator,
|
||||
defaultWindow,
|
||||
executeTransition,
|
||||
extendRef,
|
||||
formatDate,
|
||||
formatTimeAgo,
|
||||
get,
|
||||
getLifeCycleTarget,
|
||||
getSSRHandler,
|
||||
hasOwn,
|
||||
hyphenate,
|
||||
identity,
|
||||
increaseWithUnit,
|
||||
injectLocal,
|
||||
invoke,
|
||||
isClient,
|
||||
isDef,
|
||||
isDefined,
|
||||
isIOS,
|
||||
isObject,
|
||||
isWorker,
|
||||
makeDestructurable,
|
||||
mapGamepadToXbox360Controller,
|
||||
noop,
|
||||
normalizeDate,
|
||||
notNullish,
|
||||
now,
|
||||
objectEntries,
|
||||
objectOmit,
|
||||
objectPick,
|
||||
onClickOutside,
|
||||
onElementRemoval,
|
||||
onKeyDown,
|
||||
onKeyPressed,
|
||||
onKeyStroke,
|
||||
onKeyUp,
|
||||
onLongPress,
|
||||
onStartTyping,
|
||||
pausableFilter,
|
||||
promiseTimeout,
|
||||
provideLocal,
|
||||
provideSSRWidth,
|
||||
pxValue,
|
||||
rand,
|
||||
reactify,
|
||||
reactifyObject,
|
||||
reactiveComputed,
|
||||
reactiveOmit,
|
||||
reactivePick,
|
||||
refAutoReset,
|
||||
refDebounced,
|
||||
refDefault,
|
||||
refThrottled,
|
||||
refWithControl,
|
||||
resolveRef,
|
||||
resolveUnref,
|
||||
set,
|
||||
setSSRHandler,
|
||||
syncRef,
|
||||
syncRefs,
|
||||
templateRef,
|
||||
throttleFilter,
|
||||
timestamp,
|
||||
toArray,
|
||||
toReactive,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
tryOnBeforeMount,
|
||||
tryOnBeforeUnmount,
|
||||
tryOnMounted,
|
||||
tryOnScopeDispose,
|
||||
tryOnUnmounted,
|
||||
unrefElement,
|
||||
until,
|
||||
useActiveElement,
|
||||
useAnimate,
|
||||
useArrayDifference,
|
||||
useArrayEvery,
|
||||
useArrayFilter,
|
||||
useArrayFind,
|
||||
useArrayFindIndex,
|
||||
useArrayFindLast,
|
||||
useArrayIncludes,
|
||||
useArrayJoin,
|
||||
useArrayMap,
|
||||
useArrayReduce,
|
||||
useArraySome,
|
||||
useArrayUnique,
|
||||
useAsyncQueue,
|
||||
useAsyncState,
|
||||
useBase64,
|
||||
useBattery,
|
||||
useBluetooth,
|
||||
useBreakpoints,
|
||||
useBroadcastChannel,
|
||||
useBrowserLocation,
|
||||
useCached,
|
||||
useClipboard,
|
||||
useClipboardItems,
|
||||
useCloned,
|
||||
useColorMode,
|
||||
useConfirmDialog,
|
||||
useCountdown,
|
||||
useCounter,
|
||||
useCssVar,
|
||||
useCurrentElement,
|
||||
useCycleList,
|
||||
useDark,
|
||||
useDateFormat,
|
||||
useDebounceFn,
|
||||
useDebouncedRefHistory,
|
||||
useDeviceMotion,
|
||||
useDeviceOrientation,
|
||||
useDevicePixelRatio,
|
||||
useDevicesList,
|
||||
useDisplayMedia,
|
||||
useDocumentVisibility,
|
||||
useDraggable,
|
||||
useDropZone,
|
||||
useElementBounding,
|
||||
useElementByPoint,
|
||||
useElementHover,
|
||||
useElementSize,
|
||||
useElementVisibility,
|
||||
useEventBus,
|
||||
useEventListener,
|
||||
useEventSource,
|
||||
useEyeDropper,
|
||||
useFavicon,
|
||||
useFetch,
|
||||
useFileDialog,
|
||||
useFileSystemAccess,
|
||||
useFocus,
|
||||
useFocusWithin,
|
||||
useFps,
|
||||
useFullscreen,
|
||||
useGamepad,
|
||||
useGeolocation,
|
||||
useIdle,
|
||||
useImage,
|
||||
useInfiniteScroll,
|
||||
useIntersectionObserver,
|
||||
useInterval,
|
||||
useIntervalFn,
|
||||
useKeyModifier,
|
||||
useLastChanged,
|
||||
useLocalStorage,
|
||||
useMagicKeys,
|
||||
useManualRefHistory,
|
||||
useMediaControls,
|
||||
useMediaQuery,
|
||||
useMemoize,
|
||||
useMemory,
|
||||
useMounted,
|
||||
useMouse,
|
||||
useMouseInElement,
|
||||
useMousePressed,
|
||||
useMutationObserver,
|
||||
useNavigatorLanguage,
|
||||
useNetwork,
|
||||
useNow,
|
||||
useObjectUrl,
|
||||
useOffsetPagination,
|
||||
useOnline,
|
||||
usePageLeave,
|
||||
useParallax,
|
||||
useParentElement,
|
||||
usePerformanceObserver,
|
||||
usePermission,
|
||||
usePointer,
|
||||
usePointerLock,
|
||||
usePointerSwipe,
|
||||
usePreferredColorScheme,
|
||||
usePreferredContrast,
|
||||
usePreferredDark,
|
||||
usePreferredLanguages,
|
||||
usePreferredReducedMotion,
|
||||
usePreferredReducedTransparency,
|
||||
usePrevious,
|
||||
useRafFn,
|
||||
useRefHistory,
|
||||
useResizeObserver,
|
||||
useSSRWidth,
|
||||
useScreenOrientation,
|
||||
useScreenSafeArea,
|
||||
useScriptTag,
|
||||
useScroll,
|
||||
useScrollLock,
|
||||
useSessionStorage,
|
||||
useShare,
|
||||
useSorted,
|
||||
useSpeechRecognition,
|
||||
useSpeechSynthesis,
|
||||
useStepper,
|
||||
useStorage,
|
||||
useStorageAsync,
|
||||
useStyleTag,
|
||||
useSupported,
|
||||
useSwipe,
|
||||
useTemplateRefsList,
|
||||
useTextDirection,
|
||||
useTextSelection,
|
||||
useTextareaAutosize,
|
||||
useThrottleFn,
|
||||
useThrottledRefHistory,
|
||||
useTimeAgo,
|
||||
useTimeout,
|
||||
useTimeoutFn,
|
||||
useTimeoutPoll,
|
||||
useTimestamp,
|
||||
useTitle,
|
||||
useToNumber,
|
||||
useToString,
|
||||
useToggle,
|
||||
useTransition,
|
||||
useUrlSearchParams,
|
||||
useUserMedia,
|
||||
useVModel,
|
||||
useVModels,
|
||||
useVibrate,
|
||||
useVirtualList,
|
||||
useWakeLock,
|
||||
useWebNotification,
|
||||
useWebSocket,
|
||||
useWebWorker,
|
||||
useWebWorkerFn,
|
||||
useWindowFocus,
|
||||
useWindowScroll,
|
||||
useWindowSize,
|
||||
watchArray,
|
||||
watchAtMost,
|
||||
watchDebounced,
|
||||
watchDeep,
|
||||
watchIgnorable,
|
||||
watchImmediate,
|
||||
watchOnce,
|
||||
watchPausable,
|
||||
watchThrottled,
|
||||
watchTriggerable,
|
||||
watchWithFilter,
|
||||
whenever
|
||||
} from "./chunk-RLEUDPPB.js";
|
||||
import "./chunk-3S55Y3P7.js";
|
||||
export {
|
||||
DefaultMagicKeysAliasMap,
|
||||
StorageSerializers,
|
||||
TransitionPresets,
|
||||
assert,
|
||||
computedAsync as asyncComputed,
|
||||
refAutoReset as autoResetRef,
|
||||
breakpointsAntDesign,
|
||||
breakpointsBootstrapV5,
|
||||
breakpointsElement,
|
||||
breakpointsMasterCss,
|
||||
breakpointsPrimeFlex,
|
||||
breakpointsQuasar,
|
||||
breakpointsSematic,
|
||||
breakpointsTailwind,
|
||||
breakpointsVuetify,
|
||||
breakpointsVuetifyV2,
|
||||
breakpointsVuetifyV3,
|
||||
bypassFilter,
|
||||
camelize,
|
||||
clamp,
|
||||
cloneFnJSON,
|
||||
computedAsync,
|
||||
computedEager,
|
||||
computedInject,
|
||||
computedWithControl,
|
||||
containsProp,
|
||||
computedWithControl as controlledComputed,
|
||||
controlledRef,
|
||||
createEventHook,
|
||||
createFetch,
|
||||
createFilterWrapper,
|
||||
createGlobalState,
|
||||
createInjectionState,
|
||||
reactify as createReactiveFn,
|
||||
createRef,
|
||||
createReusableTemplate,
|
||||
createSharedComposable,
|
||||
createSingletonPromise,
|
||||
createTemplatePromise,
|
||||
createUnrefFn,
|
||||
customStorageEventName,
|
||||
debounceFilter,
|
||||
refDebounced as debouncedRef,
|
||||
watchDebounced as debouncedWatch,
|
||||
defaultDocument,
|
||||
defaultLocation,
|
||||
defaultNavigator,
|
||||
defaultWindow,
|
||||
computedEager as eagerComputed,
|
||||
executeTransition,
|
||||
extendRef,
|
||||
formatDate,
|
||||
formatTimeAgo,
|
||||
get,
|
||||
getLifeCycleTarget,
|
||||
getSSRHandler,
|
||||
hasOwn,
|
||||
hyphenate,
|
||||
identity,
|
||||
watchIgnorable as ignorableWatch,
|
||||
increaseWithUnit,
|
||||
injectLocal,
|
||||
invoke,
|
||||
isClient,
|
||||
isDef,
|
||||
isDefined,
|
||||
isIOS,
|
||||
isObject,
|
||||
isWorker,
|
||||
makeDestructurable,
|
||||
mapGamepadToXbox360Controller,
|
||||
noop,
|
||||
normalizeDate,
|
||||
notNullish,
|
||||
now,
|
||||
objectEntries,
|
||||
objectOmit,
|
||||
objectPick,
|
||||
onClickOutside,
|
||||
onElementRemoval,
|
||||
onKeyDown,
|
||||
onKeyPressed,
|
||||
onKeyStroke,
|
||||
onKeyUp,
|
||||
onLongPress,
|
||||
onStartTyping,
|
||||
pausableFilter,
|
||||
watchPausable as pausableWatch,
|
||||
promiseTimeout,
|
||||
provideLocal,
|
||||
provideSSRWidth,
|
||||
pxValue,
|
||||
rand,
|
||||
reactify,
|
||||
reactifyObject,
|
||||
reactiveComputed,
|
||||
reactiveOmit,
|
||||
reactivePick,
|
||||
refAutoReset,
|
||||
refDebounced,
|
||||
refDefault,
|
||||
refThrottled,
|
||||
refWithControl,
|
||||
resolveRef,
|
||||
resolveUnref,
|
||||
set,
|
||||
setSSRHandler,
|
||||
syncRef,
|
||||
syncRefs,
|
||||
templateRef,
|
||||
throttleFilter,
|
||||
refThrottled as throttledRef,
|
||||
watchThrottled as throttledWatch,
|
||||
timestamp,
|
||||
toArray,
|
||||
toReactive,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
tryOnBeforeMount,
|
||||
tryOnBeforeUnmount,
|
||||
tryOnMounted,
|
||||
tryOnScopeDispose,
|
||||
tryOnUnmounted,
|
||||
unrefElement,
|
||||
until,
|
||||
useActiveElement,
|
||||
useAnimate,
|
||||
useArrayDifference,
|
||||
useArrayEvery,
|
||||
useArrayFilter,
|
||||
useArrayFind,
|
||||
useArrayFindIndex,
|
||||
useArrayFindLast,
|
||||
useArrayIncludes,
|
||||
useArrayJoin,
|
||||
useArrayMap,
|
||||
useArrayReduce,
|
||||
useArraySome,
|
||||
useArrayUnique,
|
||||
useAsyncQueue,
|
||||
useAsyncState,
|
||||
useBase64,
|
||||
useBattery,
|
||||
useBluetooth,
|
||||
useBreakpoints,
|
||||
useBroadcastChannel,
|
||||
useBrowserLocation,
|
||||
useCached,
|
||||
useClipboard,
|
||||
useClipboardItems,
|
||||
useCloned,
|
||||
useColorMode,
|
||||
useConfirmDialog,
|
||||
useCountdown,
|
||||
useCounter,
|
||||
useCssVar,
|
||||
useCurrentElement,
|
||||
useCycleList,
|
||||
useDark,
|
||||
useDateFormat,
|
||||
refDebounced as useDebounce,
|
||||
useDebounceFn,
|
||||
useDebouncedRefHistory,
|
||||
useDeviceMotion,
|
||||
useDeviceOrientation,
|
||||
useDevicePixelRatio,
|
||||
useDevicesList,
|
||||
useDisplayMedia,
|
||||
useDocumentVisibility,
|
||||
useDraggable,
|
||||
useDropZone,
|
||||
useElementBounding,
|
||||
useElementByPoint,
|
||||
useElementHover,
|
||||
useElementSize,
|
||||
useElementVisibility,
|
||||
useEventBus,
|
||||
useEventListener,
|
||||
useEventSource,
|
||||
useEyeDropper,
|
||||
useFavicon,
|
||||
useFetch,
|
||||
useFileDialog,
|
||||
useFileSystemAccess,
|
||||
useFocus,
|
||||
useFocusWithin,
|
||||
useFps,
|
||||
useFullscreen,
|
||||
useGamepad,
|
||||
useGeolocation,
|
||||
useIdle,
|
||||
useImage,
|
||||
useInfiniteScroll,
|
||||
useIntersectionObserver,
|
||||
useInterval,
|
||||
useIntervalFn,
|
||||
useKeyModifier,
|
||||
useLastChanged,
|
||||
useLocalStorage,
|
||||
useMagicKeys,
|
||||
useManualRefHistory,
|
||||
useMediaControls,
|
||||
useMediaQuery,
|
||||
useMemoize,
|
||||
useMemory,
|
||||
useMounted,
|
||||
useMouse,
|
||||
useMouseInElement,
|
||||
useMousePressed,
|
||||
useMutationObserver,
|
||||
useNavigatorLanguage,
|
||||
useNetwork,
|
||||
useNow,
|
||||
useObjectUrl,
|
||||
useOffsetPagination,
|
||||
useOnline,
|
||||
usePageLeave,
|
||||
useParallax,
|
||||
useParentElement,
|
||||
usePerformanceObserver,
|
||||
usePermission,
|
||||
usePointer,
|
||||
usePointerLock,
|
||||
usePointerSwipe,
|
||||
usePreferredColorScheme,
|
||||
usePreferredContrast,
|
||||
usePreferredDark,
|
||||
usePreferredLanguages,
|
||||
usePreferredReducedMotion,
|
||||
usePreferredReducedTransparency,
|
||||
usePrevious,
|
||||
useRafFn,
|
||||
useRefHistory,
|
||||
useResizeObserver,
|
||||
useSSRWidth,
|
||||
useScreenOrientation,
|
||||
useScreenSafeArea,
|
||||
useScriptTag,
|
||||
useScroll,
|
||||
useScrollLock,
|
||||
useSessionStorage,
|
||||
useShare,
|
||||
useSorted,
|
||||
useSpeechRecognition,
|
||||
useSpeechSynthesis,
|
||||
useStepper,
|
||||
useStorage,
|
||||
useStorageAsync,
|
||||
useStyleTag,
|
||||
useSupported,
|
||||
useSwipe,
|
||||
useTemplateRefsList,
|
||||
useTextDirection,
|
||||
useTextSelection,
|
||||
useTextareaAutosize,
|
||||
refThrottled as useThrottle,
|
||||
useThrottleFn,
|
||||
useThrottledRefHistory,
|
||||
useTimeAgo,
|
||||
useTimeout,
|
||||
useTimeoutFn,
|
||||
useTimeoutPoll,
|
||||
useTimestamp,
|
||||
useTitle,
|
||||
useToNumber,
|
||||
useToString,
|
||||
useToggle,
|
||||
useTransition,
|
||||
useUrlSearchParams,
|
||||
useUserMedia,
|
||||
useVModel,
|
||||
useVModels,
|
||||
useVibrate,
|
||||
useVirtualList,
|
||||
useWakeLock,
|
||||
useWebNotification,
|
||||
useWebSocket,
|
||||
useWebWorker,
|
||||
useWebWorkerFn,
|
||||
useWindowFocus,
|
||||
useWindowScroll,
|
||||
useWindowSize,
|
||||
watchArray,
|
||||
watchAtMost,
|
||||
watchDebounced,
|
||||
watchDeep,
|
||||
watchIgnorable,
|
||||
watchImmediate,
|
||||
watchOnce,
|
||||
watchPausable,
|
||||
watchThrottled,
|
||||
watchTriggerable,
|
||||
watchWithFilter,
|
||||
whenever
|
||||
};
|
||||
//# sourceMappingURL=vitepress___@vueuse_core.js.map
|
||||
7
src/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [],
|
||||
"sourcesContent": [],
|
||||
"mappings": "",
|
||||
"names": []
|
||||
}
|
||||
347
src/docs/.vitepress/cache/deps/vue.js
vendored
Normal file
347
src/docs/.vitepress/cache/deps/vue.js
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
import {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBaseVNode,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
nodeOps,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
patchProp,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
} from "./chunk-3S55Y3P7.js";
|
||||
export {
|
||||
BaseTransition,
|
||||
BaseTransitionPropsValidators,
|
||||
Comment,
|
||||
DeprecationTypes,
|
||||
EffectScope,
|
||||
ErrorCodes,
|
||||
ErrorTypeStrings,
|
||||
Fragment,
|
||||
KeepAlive,
|
||||
ReactiveEffect,
|
||||
Static,
|
||||
Suspense,
|
||||
Teleport,
|
||||
Text,
|
||||
TrackOpTypes,
|
||||
Transition,
|
||||
TransitionGroup,
|
||||
TriggerOpTypes,
|
||||
VueElement,
|
||||
assertNumber,
|
||||
callWithAsyncErrorHandling,
|
||||
callWithErrorHandling,
|
||||
camelize,
|
||||
capitalize,
|
||||
cloneVNode,
|
||||
compatUtils,
|
||||
compile,
|
||||
computed,
|
||||
createApp,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createBaseVNode as createElementVNode,
|
||||
createHydrationRenderer,
|
||||
createPropsRestProxy,
|
||||
createRenderer,
|
||||
createSSRApp,
|
||||
createSlots,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
createVNode,
|
||||
customRef,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
defineCustomElement,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
defineModel,
|
||||
defineOptions,
|
||||
defineProps,
|
||||
defineSSRCustomElement,
|
||||
defineSlots,
|
||||
devtools,
|
||||
effect,
|
||||
effectScope,
|
||||
getCurrentInstance,
|
||||
getCurrentScope,
|
||||
getCurrentWatcher,
|
||||
getTransitionRawChildren,
|
||||
guardReactiveProps,
|
||||
h,
|
||||
handleError,
|
||||
hasInjectionContext,
|
||||
hydrate,
|
||||
hydrateOnIdle,
|
||||
hydrateOnInteraction,
|
||||
hydrateOnMediaQuery,
|
||||
hydrateOnVisible,
|
||||
initCustomFormatter,
|
||||
initDirectivesForSSR,
|
||||
inject,
|
||||
isMemoSame,
|
||||
isProxy,
|
||||
isReactive,
|
||||
isReadonly,
|
||||
isRef,
|
||||
isRuntimeOnly,
|
||||
isShallow,
|
||||
isVNode,
|
||||
markRaw,
|
||||
mergeDefaults,
|
||||
mergeModels,
|
||||
mergeProps,
|
||||
nextTick,
|
||||
nodeOps,
|
||||
normalizeClass,
|
||||
normalizeProps,
|
||||
normalizeStyle,
|
||||
onActivated,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
onBeforeUpdate,
|
||||
onDeactivated,
|
||||
onErrorCaptured,
|
||||
onMounted,
|
||||
onRenderTracked,
|
||||
onRenderTriggered,
|
||||
onScopeDispose,
|
||||
onServerPrefetch,
|
||||
onUnmounted,
|
||||
onUpdated,
|
||||
onWatcherCleanup,
|
||||
openBlock,
|
||||
patchProp,
|
||||
popScopeId,
|
||||
provide,
|
||||
proxyRefs,
|
||||
pushScopeId,
|
||||
queuePostFlushCb,
|
||||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
registerRuntimeCompiler,
|
||||
render,
|
||||
renderList,
|
||||
renderSlot,
|
||||
resolveComponent,
|
||||
resolveDirective,
|
||||
resolveDynamicComponent,
|
||||
resolveFilter,
|
||||
resolveTransitionHooks,
|
||||
setBlockTracking,
|
||||
setDevtoolsHook,
|
||||
setTransitionHooks,
|
||||
shallowReactive,
|
||||
shallowReadonly,
|
||||
shallowRef,
|
||||
ssrContextKey,
|
||||
ssrUtils,
|
||||
stop,
|
||||
toDisplayString,
|
||||
toHandlerKey,
|
||||
toHandlers,
|
||||
toRaw,
|
||||
toRef,
|
||||
toRefs,
|
||||
toValue,
|
||||
transformVNodeArgs,
|
||||
triggerRef,
|
||||
unref,
|
||||
useAttrs,
|
||||
useCssModule,
|
||||
useCssVars,
|
||||
useHost,
|
||||
useId,
|
||||
useModel,
|
||||
useSSRContext,
|
||||
useShadowRoot,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
useTransitionState,
|
||||
vModelCheckbox,
|
||||
vModelDynamic,
|
||||
vModelRadio,
|
||||
vModelSelect,
|
||||
vModelText,
|
||||
vShow,
|
||||
version,
|
||||
warn,
|
||||
watch,
|
||||
watchEffect,
|
||||
watchPostEffect,
|
||||
watchSyncEffect,
|
||||
withAsyncContext,
|
||||
withCtx,
|
||||
withDefaults,
|
||||
withDirectives,
|
||||
withKeys,
|
||||
withMemo,
|
||||
withModifiers,
|
||||
withScopeId
|
||||
};
|
||||
//# sourceMappingURL=vue.js.map
|
||||
7
src/docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
7
src/docs/.vitepress/cache/deps/vue.js.map
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [],
|
||||
"sourcesContent": [],
|
||||
"mappings": "",
|
||||
"names": []
|
||||
}
|
||||
@@ -38,13 +38,22 @@ export default defineConfig({
|
||||
text: 'API Reference',
|
||||
items: [
|
||||
{ text: 'Quick Start', link: '/api/quick' },
|
||||
{ text: 'Signals', link: '/api/signals' },
|
||||
{ text: 'Effects', link: '/api/effects' },
|
||||
{ text: 'Storage', link: '/api/storage' },
|
||||
{ text: 'Fetch', link: '/api/fetch' },
|
||||
{ text: 'Pages', link: '/api/pages' },
|
||||
{ text: 'Components', link: '/api/components' },
|
||||
{ text: 'Routing', link: '/api/routing' },
|
||||
{ text: '$', link: '/api/$' },
|
||||
{ text: '$.html', link: '/api/html' },
|
||||
{ text: '$.mount', link: '/api/mount' },
|
||||
{ text: 'Tags', link: '/api/tags' },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Plugins',
|
||||
items: [
|
||||
{ text: 'Quick Start', link: '/plugins/quick' },
|
||||
{ text: '@core Router Plugin', link: '/plugins/core.router' },
|
||||
{ text: '@core UI Plugin', link: '/plugins/core.ui' },
|
||||
{ text: '@core UI Fetch', link: '/plugins/core.fetch' },
|
||||
{ text: '@core UI Storage', link: '/plugins/core.storage' },
|
||||
{ text: '@core UI Debug', link: '/plugins/core.debug' },
|
||||
{ text: 'Custom', link: '/plugins/custom' },
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
101
src/docs/api/$.md
Normal file
101
src/docs/api/$.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# The Reactive Core: `$( )`
|
||||
|
||||
The `$` function is the heart of **SigPro**. It is a **Unified Reactive Constructor** that handles state, derivations, and side effects through a single, consistent interface.
|
||||
|
||||
## 1. The Constructor: `$( input )`
|
||||
|
||||
Depending on what you pass into `$( )`, SigPro creates a different type of reactive primitive:
|
||||
|
||||
| Input Type | Result | Internal Behavior |
|
||||
| :--- | :--- | :--- |
|
||||
| **Value** (String, Number, Object...) | **Signal** | Creates a piece of mutable state. |
|
||||
| **Function** | **Computed / Effect** | Creates a derived value that tracks dependencies. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Signal (State)
|
||||
|
||||
A **Signal** is a "box" that holds a value. It provides a getter/setter function to interact with that value.
|
||||
|
||||
* **When to use:** For data that changes over time (counters, user input, toggle states, API data).
|
||||
* **Syntax:** `const $state = $(initialValue);`
|
||||
|
||||
### Example:
|
||||
```javascript
|
||||
const $name = $("Alice");
|
||||
|
||||
// Read the value (Getter)
|
||||
console.log($name()); // "Alice"
|
||||
|
||||
// Update the value (Setter)
|
||||
$name("Bob");
|
||||
|
||||
// Update based on previous value
|
||||
$name(current => current + " Smith");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Computed (Derived State)
|
||||
|
||||
When you pass a **function** to `$( )` that **returns a value**, SigPro creates a **Computed Signal**. It automatically tracks which signals are used inside it and re-runs only when they change.
|
||||
|
||||
* **When to use:** For values that depend on other signals (totals, filtered lists, formatted strings).
|
||||
* **Syntax:** `const $derived = $(() => logic);`
|
||||
|
||||
### Example:
|
||||
```javascript
|
||||
const $price = $(100);
|
||||
const $qty = $(2);
|
||||
|
||||
// Automatically tracks $price and $qty
|
||||
const $total = $(() => $price() * $qty());
|
||||
|
||||
console.log($total()); // 200
|
||||
|
||||
$qty(3); // $total updates to 300 automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Effects (Side Effects)
|
||||
|
||||
An **Effect** is a function passed to `$( )` that **does not return a value** (or returns `undefined`). SigPro treats this as a subscription that performs an action whenever its dependencies change.
|
||||
|
||||
* **When to use:** For DOM manipulations, logging, or syncing with external APIs (LocalStorage, Fetch).
|
||||
* **Syntax:** `$(() => { action });`
|
||||
|
||||
### Example:
|
||||
```javascript
|
||||
const $theme = $("light");
|
||||
|
||||
// This effect runs every time $theme changes
|
||||
$(() => {
|
||||
document.body.className = $theme();
|
||||
console.log("Theme updated to:", $theme());
|
||||
});
|
||||
|
||||
$theme("dark"); // Logs: Theme updated to: dark
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Summary Table: Usage Guide
|
||||
|
||||
| Primitive | Logic Type | Returns Value? | Typical Use Case |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Signal** | Static | Yes (Mutable) | `const $user = $("Guest")` |
|
||||
| **Computed** | Read-only | Yes (Automatic) | `const $isLoggedIn = $(() => $user() !== "Guest")` |
|
||||
| **Effect** | Imperative | No | `$(() => localStorage.setItem('user', $user()))` |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 💡 Pro Tip: Naming Convention
|
||||
In SigPro, we use the **`$` prefix** (e.g., `$count`) for variables that hold a reactive function. This makes it easy to distinguish between a standard variable and a reactive one at a glance:
|
||||
|
||||
```javascript
|
||||
let count = 0; // Static
|
||||
const $count = $(0); // Reactive (Function)
|
||||
```
|
||||
103
src/docs/api/html.md
Normal file
103
src/docs/api/html.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Rendering Engine: `$.html`
|
||||
|
||||
The `$.html` function is the architect of your UI. It creates standard HTML elements and wires them directly to your signals without the need for a Virtual DOM.
|
||||
|
||||
## 1. Syntax: `$.html(tag, [props], [content])`
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **tag** | `string` | **Yes** | Any valid HTML5 tag (e.g., `'div'`, `'button'`, `'input'`). |
|
||||
| **props** | `Object` | No | Attributes, event listeners, and reactive bindings. |
|
||||
| **content** | `any` | No | Text, Nodes, Arrays, or Reactive Functions. |
|
||||
|
||||
### Example:
|
||||
```javascript
|
||||
const myButton = $.html('button', { class: 'btn-primary' }, 'Click me');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Global Tag Helpers
|
||||
|
||||
To avoid repetitive `$.html` calls, SigPro automatically exposes common tags to the global `window` object. This allows for a clean, declarative syntax.
|
||||
|
||||
```javascript
|
||||
// Instead of $.html('div', ...), just use:
|
||||
div({ id: 'wrapper' }, [
|
||||
h1("Welcome"),
|
||||
p("This is SigPro.")
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Handling Properties & Attributes
|
||||
|
||||
SigPro distinguishes between static attributes and reactive bindings using the **`$` prefix**.
|
||||
|
||||
### Static vs. Reactive Attributes
|
||||
* **Static:** Applied once during creation.
|
||||
* **Reactive (`$`):** Automatically updates the DOM when the signal changes.
|
||||
|
||||
| Property | Syntax | Result |
|
||||
| :--- | :--- | :--- |
|
||||
| **Attribute** | `{ id: 'main' }` | `id="main"` |
|
||||
| **Event** | `{ onclick: fn }` | Adds an event listener. |
|
||||
| **Reactive Attr** | `{ $class: $theme }` | Updates `class` whenever `$theme()` changes. |
|
||||
| **Boolean Attr** | `{ $disabled: $isBusy }` | Toggles the `disabled` attribute automatically. |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. Two-Way Data Binding
|
||||
|
||||
For form inputs, SigPro provides a powerful shortcut using `$value` or `$checked`. It automatically handles the event listening and the value synchronization.
|
||||
|
||||
```javascript
|
||||
const $text = $("Type here...");
|
||||
|
||||
input({
|
||||
type: 'text',
|
||||
$value: $text // Syncs input -> signal and signal -> input
|
||||
});
|
||||
|
||||
p(["You typed: ", $text]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Reactive Content (Dynamic Children)
|
||||
|
||||
The `content` argument is incredibly flexible. If you pass a **function**, SigPro treats it as a reactive "portal" that re-renders only that specific part of the DOM.
|
||||
|
||||
### Text & Nodes
|
||||
```javascript
|
||||
const $count = $(0);
|
||||
|
||||
// Text node updates surgically
|
||||
div(["Count: ", $count]);
|
||||
|
||||
// Conditional rendering with a function
|
||||
div(() => {
|
||||
return $count() > 10
|
||||
? h1("High Score!")
|
||||
: p("Keep going...");
|
||||
});
|
||||
```
|
||||
|
||||
### The "Guillotine" (Performance Tip)
|
||||
When a reactive function in the content returns a **new Node**, SigPro uses `replaceWith()` to swap the old node for the new one. This ensures that:
|
||||
1. The update is nearly instantaneous.
|
||||
2. The old node is correctly garbage-collected.
|
||||
|
||||
---
|
||||
|
||||
## 6. Summary: Content Types
|
||||
|
||||
| Input | Behavior |
|
||||
| :--- | :--- |
|
||||
| **String / Number** | Appended as a TextNode. |
|
||||
| **HTMLElement** | Appended directly to the parent. |
|
||||
| **Array** | Each item is processed and appended in order. |
|
||||
| **Function `() => ...`** | Creates a **live reactive zone** that updates automatically. |
|
||||
108
src/docs/api/mount.md
Normal file
108
src/docs/api/mount.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Application Mounter: `$.mount`
|
||||
|
||||
The `$.mount` function is the entry point of your reactive world. It takes a **SigPro component** (or a plain DOM node) and injects it into the real document.
|
||||
|
||||
## 1. Syntax: `$.mount(node, [target])`
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **node** | `HTMLElement` or `Function` | **Required** | The component or element to render. |
|
||||
| **target** | `string` or `HTMLElement` | `document.body` | Where to mount the app (CSS selector or Element). |
|
||||
|
||||
---
|
||||
|
||||
## 2. Usage Scenarios
|
||||
|
||||
### A. The "Clean Slate" (Main Entry)
|
||||
In a modern app (like our `main.js` example), you usually want to control the entire page. By default, `$.mount` clears the target's existing HTML before mounting.
|
||||
|
||||
```javascript
|
||||
// src/main.js
|
||||
import { $ } from 'SigPro';
|
||||
import App from './App.js';
|
||||
|
||||
$.mount(App); // Mounts to <body> by default
|
||||
```
|
||||
|
||||
### B. Targeting a Specific Container
|
||||
If you have an existing HTML structure and only want **SigPro** to manage a specific part (like a `#root` div), pass a CSS selector or a reference.
|
||||
|
||||
```html
|
||||
<div id="sidebar"></div>
|
||||
<div id="app-root"></div>
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Local mount to a specific ID
|
||||
$.mount(MyComponent, '#app-root');
|
||||
|
||||
// Or using a direct DOM reference
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
$.mount(SidebarComponent, sidebar);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Mounting with Pure HTML
|
||||
One of SigPro's strengths is that it works perfectly alongside "Old School" HTML. You can create a reactive "island" inside a static page.
|
||||
|
||||
```javascript
|
||||
// A small reactive widget in a static .js file
|
||||
const CounterWidget = () => {
|
||||
const $c = $(0);
|
||||
return button({ onclick: () => $c(v => v + 1) }, [
|
||||
"Clicks: ", $c
|
||||
]);
|
||||
};
|
||||
|
||||
// Mount it into an existing div in your HTML
|
||||
$.mount(CounterWidget, '#counter-container');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. How it Works (The "Wipe" Logic)
|
||||
When `$.mount` is called, it performs two critical steps:
|
||||
|
||||
1. **Clearance:** It sets `target.innerHTML = ''`. This ensures no "zombie" HTML from previous renders or static placeholders interferes with your app.
|
||||
2. **Injection:** It appends your component. If you passed a **Function**, it executes it first to get the DOM node.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. Global vs. Local Scope
|
||||
|
||||
### Global (The "Framework" Way)
|
||||
In a standard Vite/ESM project, you initialize SigPro globally in `main.js`. This makes the `$` and the tag helpers (`div`, `button`, etc.) available everywhere in your project.
|
||||
|
||||
```javascript
|
||||
// main.js - Global Initialization
|
||||
import 'SigPro';
|
||||
|
||||
// Now any other file can just use:
|
||||
$.mount(() => h1("Global App"));
|
||||
```
|
||||
|
||||
### Local (The "Library" Way)
|
||||
If you are worried about polluting the global `window` object, you can import and use SigPro locally within a specific module.
|
||||
|
||||
```javascript
|
||||
// widget.js - Local usage
|
||||
import { $ } from 'SigPro';
|
||||
|
||||
const myNode = $.html('div', 'Local Widget');
|
||||
$.mount(myNode, '#widget-target');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Summary Cheat Sheet
|
||||
|
||||
| Goal | Code |
|
||||
| :--- | :--- |
|
||||
| **Mount to body** | `$.mount(App)` |
|
||||
| **Mount to ID** | `$.mount(App, '#id')` |
|
||||
| **Mount to Element** | `$.mount(App, myElement)` |
|
||||
| **Reactive Widget** | `$.mount(() => div("Hi"), '#widget')` |
|
||||
|
||||
99
src/docs/api/quick.md
Normal file
99
src/docs/api/quick.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Quick API Reference ⚡
|
||||
|
||||
This is a high-level summary of the **SigPro** core API. For detailed guides and edge cases, please refer to the specific documentation for each module.
|
||||
|
||||
## 1. Core Reactivity: `$( )`
|
||||
|
||||
The `$` function is a polymorphic constructor. It creates **Signals** (state) or **Computed Effects** (logic) based on the input type.
|
||||
|
||||
| Usage | Input Type | Returns | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Signal** | `any` | `Function` | A getter/setter for reactive state. |
|
||||
| **Computed** | `Function` | `Function` | A read-only signal that auto-updates when its dependencies change. |
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
const $count = $(0); // Signal
|
||||
const $double = $(() => $count() * 2); // Computed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Rendering Engine: `$.html`
|
||||
|
||||
SigPro uses a hyperscript-style engine to create live DOM nodes.
|
||||
|
||||
| Argument | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **tag** | `string` | Yes | Standard HTML tag (e.g., 'div', 'button'). |
|
||||
| **props** | `Object` | No | Attributes (`id`), Events (`onclick`), or Reactive Props (`$value`). |
|
||||
| **content** | `any` | No | String, Node, Array, or Reactive Function. |
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
$.html('button', { onclick: () => alert('Hi!') }, 'Click Me');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Global Helpers (Tag Proxies)
|
||||
|
||||
To keep your code clean, SigPro automatically exposes common HTML tags to the global scope.
|
||||
|
||||
| Category | Available Tags |
|
||||
| :--- | :--- |
|
||||
| **Layout** | `div`, `section`, `main`, `nav`, `header`, `footer`, `span` |
|
||||
| **Typography** | `h1`, `h2`, `h3`, `p`, `label`, `a`, `li`, `ul`, `ol` |
|
||||
| **Forms** | `input`, `button`, `form`, `select`, `option` |
|
||||
| **Media** | `img`, `video`, `audio`, `canvas` |
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// No imports needed!
|
||||
div([
|
||||
h1("Title"),
|
||||
button("Ok")
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Mounting & Plugins
|
||||
|
||||
Methods to initialize your application and extend the engine.
|
||||
|
||||
| Method | Signature | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| **`$.mount`** | `(node, target)` | Wipes the target (default: `body`) and renders the component. |
|
||||
| **`$.plugin`** | `(source)` | Registers a function or loads external `.js` scripts as plugins. |
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
$.plugin([UI, Router]);
|
||||
$.mount(App, '#root');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Reactive Syntax Cheat Sheet
|
||||
|
||||
| Feature | Syntax | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| **Text Binding** | `p(["Value: ", $sig])` | Updates text content automatically. |
|
||||
| **Attributes** | `div({ id: $sig })` | Static attribute assignment. |
|
||||
| **Reactive Attr** | `div({ $class: $sig })` | Attribute updates when `$sig` changes. |
|
||||
| **Two-way Binding**| `input({ $value: $sig })`| Syncs input value and signal automatically. |
|
||||
| **Conditional** | `div(() => $sig() > 0 ? "Yes" : "No")` | Re-renders only the content when the condition changes. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Summary Table
|
||||
|
||||
| Feature | SigPro Approach | Benefit |
|
||||
| :--- | :--- | :--- |
|
||||
| **Update Logic** | Fine-grained (Surgical) | Blazing fast updates. |
|
||||
| **DOM** | Native Nodes | Zero abstraction cost. |
|
||||
| **Syntax** | Pure JavaScript | No build-tool lock-in. |
|
||||
| **Footprint** | Modular | Load only what you use. |
|
||||
160
src/docs/api/tags.md
Normal file
160
src/docs/api/tags.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Global Tag Helpers
|
||||
|
||||
In **SigPro**, you don't need to write `$.html('div', ...)` every time. To keep your code clean and readable, the engine automatically generates global helper functions for all standard HTML tags.
|
||||
|
||||
## 1. How it Works
|
||||
|
||||
When SigPro initializes, it runs a proxy loop that creates a function for every common HTML tag and attaches it to the `window` object.
|
||||
|
||||
* **Traditional:** `$.html('button', { onclick: ... }, 'Click')`
|
||||
* **SigPro Style:** `button({ onclick: ... }, 'Click')`
|
||||
|
||||
This approach gives you a "DSL" (Domain Specific Language) that feels like HTML but is actually **pure JavaScript**.
|
||||
|
||||
---
|
||||
|
||||
## 2. The Global Registry
|
||||
|
||||
The following tags are available globally by default:
|
||||
|
||||
| Category | Available Functions |
|
||||
| :--- | :--- |
|
||||
| **Layout** | `div`, `span`, `section`, `main`, `nav`, `header`, `footer`, `article`, `aside` |
|
||||
| **Typography** | `h1`, `h2`, `h3`, `p`, `ul`, `ol`, `li`, `a`, `label`, `strong`, `em` |
|
||||
| **Forms** | `form`, `input`, `button`, `select`, `option`, `textarea` |
|
||||
| **Table** | `table`, `thead`, `tbody`, `tr`, `th`, `td` |
|
||||
| **Media** | `img`, `video`, `audio`, `canvas`, `svg` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Usage Patterns
|
||||
|
||||
The tag functions are highly flexible and accept arguments in different orders to suit your coding style.
|
||||
|
||||
### A. Attributes + Content
|
||||
The most common pattern.
|
||||
```javascript
|
||||
div({ class: 'card' }, [
|
||||
h1("Title"),
|
||||
p("Description")
|
||||
]);
|
||||
```
|
||||
|
||||
### B. Content Only
|
||||
If you don't need attributes, you can skip the object entirely.
|
||||
```javascript
|
||||
div([
|
||||
h1("Just Content"),
|
||||
p("No attributes object needed here.")
|
||||
]);
|
||||
```
|
||||
|
||||
### C. Simple Text
|
||||
For elements that only contain a string.
|
||||
```javascript
|
||||
button("Submit"); // Equivalent to <button>Submit</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Reactive Tags
|
||||
|
||||
Since these helpers are just wrappers around `$.html`, they support full reactivity out of the box.
|
||||
|
||||
```javascript
|
||||
const $loading = $(true);
|
||||
|
||||
div([
|
||||
$loading() ? span("Loading...") : h1("Data Ready!"),
|
||||
button({
|
||||
$disabled: $loading, // Reactive attribute
|
||||
onclick: () => $loading(false)
|
||||
}, "Stop Loading")
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Under the Hood
|
||||
|
||||
If you are curious about how this happens without a compiler, here is the logic inside the SigPro core:
|
||||
|
||||
```javascript
|
||||
const tags = ['div', 'span', 'p', 'button', ...];
|
||||
|
||||
tags.forEach(tag => {
|
||||
window[tag] = (props, content) => $.html(tag, props, content);
|
||||
});
|
||||
```
|
||||
|
||||
Because these are attached to `window`, they are available in any file in your project as soon as SigPro is loaded, making your components look like this:
|
||||
|
||||
```javascript
|
||||
// No imports required for tags!
|
||||
export default () =>
|
||||
section({ id: 'hero' }, [
|
||||
h1("Fast. Atomic. Simple."),
|
||||
p("Built with SigPro.")
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Full Comparison: SigPro vs. Standard HTML
|
||||
|
||||
To better understand the translation, here is a complete example of a **User Card** component. Notice how **SigPro** attributes with the `$` prefix map to reactive behavior, while standard attributes remain static.
|
||||
|
||||
::: code-group
|
||||
```javascript [SigPro (JS)]
|
||||
const $online = $(true);
|
||||
|
||||
export const UserCard = () => (
|
||||
div({ class: 'user-card' }, [
|
||||
img({ src: 'avatar.png', alt: 'User' }),
|
||||
|
||||
div({ class: 'info' }, [
|
||||
h2("John Doe"),
|
||||
p({
|
||||
$class: () => $online() ? 'status-on' : 'status-off'
|
||||
}, [
|
||||
"Status: ",
|
||||
() => $online() ? "Online" : "Offline"
|
||||
])
|
||||
]),
|
||||
|
||||
button({
|
||||
onclick: () => $online(!$online())
|
||||
}, "Toggle Status")
|
||||
])
|
||||
);
|
||||
```
|
||||
|
||||
```html [Equivalent HTML Structure]
|
||||
<div class="user-card">
|
||||
<img src="avatar.png" alt="User">
|
||||
|
||||
<div class="info">
|
||||
<h2>John Doe</h2>
|
||||
<p class="status-on">
|
||||
Status: Online
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button>Toggle Status</button>
|
||||
</div>
|
||||
```
|
||||
:::
|
||||
|
||||
### What is happening here?
|
||||
|
||||
1. **Structure:** The hierarchy is identical. `div([...])` in JS translates directly to nested tags in HTML.
|
||||
2. **Attributes:** `class` is set once. `$class` is "live"; SigPro listens to the `$online` signal and updates the class name without re-rendering the whole card.
|
||||
3. **Content:** The array `[...]` in SigPro is the equivalent of the children inside an HTML tag.
|
||||
4. **Reactivity:** The function `() => $online() ? ...` creates a **TextNode** in the HTML that changes its text content surgically whenever the signal toggles.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
1. **Destructuring:** If you prefer not to rely on global variables, you can destructure them from `window` or `$` (though in SigPro, using them globally is the intended "clean" way).
|
||||
2. **Custom Tags:** If you need a tag that isn't in the default list (like a Web Component), you can still use the base engine: `$.html('my-custom-element', { ... })`.
|
||||
@@ -1,308 +1,76 @@
|
||||
# Getting Started with SigPro 🚀
|
||||
# Getting Started
|
||||
|
||||
Welcome to SigPro! This guide will help you get up and running with the library in minutes. SigPro is a minimalist reactive library that embraces the web platform - no compilation, no virtual DOM, just pure JavaScript and intelligent reactivity.
|
||||
**SigPro** is a lightweight, atomic reactive engine designed to build modern web interfaces with zero overhead. It focuses on high performance through fine-grained reactivity.
|
||||
|
||||
## 📦 Installation
|
||||
## 1. Installation
|
||||
|
||||
Choose your preferred installation method:
|
||||
You can install SigPro via your favorite package manager:
|
||||
|
||||
```bash
|
||||
# Using npm
|
||||
npm install sigpro
|
||||
::: code-group
|
||||
```bash [npm]
|
||||
npm install SigPro
|
||||
````
|
||||
|
||||
# Using bun
|
||||
bun add sigpro
|
||||
|
||||
# Or simply copy sigpro.js to your project
|
||||
# (yes, it's that simple!)
|
||||
```bash [pnpm]
|
||||
pnpm add SigPro
|
||||
```
|
||||
|
||||
## 🎯 Core Imports
|
||||
|
||||
```javascript
|
||||
import { $, html } from 'sigpro';
|
||||
```bash [yarn]
|
||||
yarn add SigPro
|
||||
```
|
||||
|
||||
That's it! Just two imports to unlock the entire reactive system:
|
||||
- **`$`** - Creates reactive signals (the heart of reactivity)
|
||||
- **`html`** - Template literal tag for reactive DOM rendering
|
||||
|
||||
## 🧠 Understanding the Basics
|
||||
|
||||
### Signals - The Reactive Heart
|
||||
|
||||
Signals are reactive values that automatically track dependencies and update when changed:
|
||||
|
||||
```javascript
|
||||
// Create a signal with initial value
|
||||
const count = $(0);
|
||||
|
||||
// Read value (with auto dependency tracking)
|
||||
console.log(count()); // 0
|
||||
|
||||
// Set new value
|
||||
count(5);
|
||||
|
||||
// Update using previous value
|
||||
count(prev => prev + 1); // 6
|
||||
|
||||
// Create computed signals (auto-updating)
|
||||
const firstName = $('John');
|
||||
const lastName = $('Doe');
|
||||
const fullName = $(() => `${firstName()} ${lastName()}`);
|
||||
console.log(fullName()); // "John Doe"
|
||||
firstName('Jane'); // fullName() now returns "Jane Doe"
|
||||
```bash [bun]
|
||||
bun add SigPro
|
||||
```
|
||||
:::
|
||||
|
||||
### Effects - Automatic Reactions
|
||||
## 2\. Basic Usage
|
||||
|
||||
Effects automatically run and re-run when their signal dependencies change:
|
||||
The core of SigPro is the `$` function, which creates reactive state (Signals) and computed effects.
|
||||
|
||||
Create a `main.js` file and try this:
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
import { $ } from 'SigPro';
|
||||
|
||||
$.effect(() => {
|
||||
console.log(`Count is: ${count()}`);
|
||||
});
|
||||
// Logs: "Count is: 0"
|
||||
// 1. Create a reactive signal
|
||||
const $name = $("World");
|
||||
|
||||
count(1);
|
||||
// Logs: "Count is: 1"
|
||||
|
||||
// Effects can return cleanup functions
|
||||
$.effect(() => {
|
||||
const id = count();
|
||||
const timer = setInterval(() => {
|
||||
console.log(`Polling with count: ${id}`);
|
||||
}, 1000);
|
||||
// 2. Define a reactive component
|
||||
const App = () => div({ class: 'container' }, [
|
||||
h1(["Hello, ", $name, "!"]),
|
||||
|
||||
// Cleanup runs before next effect execution
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
```
|
||||
|
||||
### Rendering with `html`
|
||||
|
||||
The `html` tag creates reactive DOM fragments:
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
const isActive = $(true);
|
||||
|
||||
const fragment = html`
|
||||
<div class="counter">
|
||||
<h2>Count: ${count}</h2>
|
||||
|
||||
<!-- Event binding -->
|
||||
<button @click=${() => count(c => c + 1)}>
|
||||
Increment
|
||||
</button>
|
||||
|
||||
<!-- Boolean attributes -->
|
||||
<button ?disabled=${() => !isActive()}>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(fragment);
|
||||
```
|
||||
|
||||
## 🎨 Your First Reactive App
|
||||
|
||||
Let's build a simple todo app to see SigPro in action:
|
||||
|
||||
```javascript
|
||||
import { $, html } from 'sigpro';
|
||||
|
||||
// Create a simple todo app
|
||||
function TodoApp() {
|
||||
// Reactive state
|
||||
const todos = $(['Learn SigPro', 'Build something awesome']);
|
||||
const newTodo = $('');
|
||||
input({
|
||||
type: 'text',
|
||||
$value: $name, // Two-way binding
|
||||
placeholder: 'Enter your name...'
|
||||
}),
|
||||
|
||||
// Computed value
|
||||
const todoCount = $(() => todos().length);
|
||||
|
||||
// Add todo function
|
||||
const addTodo = () => {
|
||||
if (newTodo().trim()) {
|
||||
todos([...todos(), newTodo()]);
|
||||
newTodo('');
|
||||
}
|
||||
};
|
||||
|
||||
// Remove todo function
|
||||
const removeTodo = (index) => {
|
||||
todos(todos().filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
// Return reactive template
|
||||
return html`
|
||||
<div style="max-width: 400px; margin: 2rem auto; font-family: system-ui;">
|
||||
<h1>📝 Todo App</h1>
|
||||
|
||||
<!-- Input form -->
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 16px;">
|
||||
<input
|
||||
type="text"
|
||||
:value=${newTodo}
|
||||
placeholder="Add a new todo..."
|
||||
style="flex: 1; padding: 8px; border: 1px solid #ddd; border-radius: 4px;"
|
||||
@keydown.enter=${addTodo}
|
||||
/>
|
||||
<button
|
||||
@click=${addTodo}
|
||||
style="padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Todo count -->
|
||||
<p>Total todos: ${todoCount}</p>
|
||||
|
||||
<!-- Todo list -->
|
||||
<ul style="list-style: none; padding: 0;">
|
||||
${() => todos().map((todo, index) => html`
|
||||
<li style="display: flex; justify-content: space-between; align-items: center; padding: 8px; margin: 4px 0; background: #f5f5f5; border-radius: 4px;">
|
||||
<span>${todo}</span>
|
||||
<button
|
||||
@click=${() => removeTodo(index)}
|
||||
style="padding: 4px 8px; background: #ff4444; color: white; border: none; border-radius: 4px; cursor: pointer;"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</li>
|
||||
`)}
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
button({
|
||||
onclick: () => $name("SigPro")
|
||||
}, "Set to SigPro")
|
||||
]);
|
||||
|
||||
// Mount the app
|
||||
document.body.appendChild(TodoApp());
|
||||
// 3. Mount the application
|
||||
$.mount(App, '#app');
|
||||
```
|
||||
|
||||
## 🎯 Key Concepts
|
||||
## 3\. How it Works
|
||||
|
||||
### 1. **Signal Patterns**
|
||||
SigPro doesn't use a Virtual DOM. Instead, it creates real DOM nodes and binds them directly to your data:
|
||||
|
||||
| Pattern | Example | Use Case |
|
||||
|---------|---------|----------|
|
||||
| Basic signal | `const count = $(0)` | Simple values |
|
||||
| Computed | `$( () => first() + last() )` | Derived values |
|
||||
| Signal update | `count(5)` | Direct set |
|
||||
| Functional update | `count(prev => prev + 1)` | Based on previous |
|
||||
1. **Signals**: `$(value)` creates a getter/setter function.
|
||||
2. **Reactivity**: When you pass a signal or a function to a DOM element, SigPro automatically creates a subscription.
|
||||
3. **Fine-Grained Updates**: Only the specific text node or attribute linked to the signal updates when the value changes.
|
||||
|
||||
### 2. **Effect Patterns**
|
||||
## 4\. Global Tags
|
||||
|
||||
By default, SigPro exports common HTML tags to the global scope (`window`) when initialized. This allows you to write clean, declarative UI without importing every single tag:
|
||||
|
||||
```javascript
|
||||
// Basic effect
|
||||
$.effect(() => console.log(count()));
|
||||
|
||||
// Effect with cleanup
|
||||
$.effect(() => {
|
||||
const timer = setInterval(() => {}, 1000);
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
|
||||
// Stopping an effect
|
||||
const stop = $.effect(() => {});
|
||||
stop(); // Effect won't run again
|
||||
// Instead of $.html('div', ...), just use:
|
||||
div([
|
||||
h1("Clean Syntax"),
|
||||
p("No more boilerplate.")
|
||||
]);
|
||||
```
|
||||
|
||||
### 3. **HTML Directives**
|
||||
|
||||
| Directive | Example | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `@event` | `@click=${handler}` | Event listeners |
|
||||
| `:property` | `:value=${signal}` | Two-way binding |
|
||||
| `?attribute` | `?disabled=${signal}` | Boolean attributes |
|
||||
| `.property` | `.scrollTop=${value}` | DOM properties |
|
||||
|
||||
## 💡 Pro Tips for Beginners
|
||||
|
||||
### 1. **Start Simple**
|
||||
```javascript
|
||||
// Begin with basic signals
|
||||
const name = $('World');
|
||||
html`<h1>Hello, ${name}!</h1>`;
|
||||
```
|
||||
|
||||
### 2. **Use Computed Signals for Derived State**
|
||||
```javascript
|
||||
// ❌ Don't compute in template
|
||||
html`<p>Total: ${items().length * price()}</p>`;
|
||||
|
||||
// ✅ Compute with signals
|
||||
const total = $(() => items().length * price());
|
||||
html`<p>Total: ${total}</p>`;
|
||||
```
|
||||
|
||||
### 3. **Leverage Effects for Side Effects**
|
||||
```javascript
|
||||
// Auto-save to localStorage
|
||||
$.effect(() => {
|
||||
localStorage.setItem('draft', JSON.stringify(draft()));
|
||||
});
|
||||
```
|
||||
|
||||
## 🔧 VS Code Setup
|
||||
|
||||
For the best development experience, install these VS Code extensions:
|
||||
|
||||
- **lit-html** - Adds syntax highlighting for `html` tagged templates
|
||||
- **Prettier** - Automatically formats your template literals
|
||||
|
||||
```javascript
|
||||
// With lit-html extension, you get full syntax highlighting!
|
||||
html`
|
||||
<div style="color: #ff4444; background: linear-gradient(45deg, blue, green)">
|
||||
<h1>Beautiful highlighted template</h1>
|
||||
</div>
|
||||
`
|
||||
```
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
Here's a recommended structure for larger apps:
|
||||
|
||||
```
|
||||
my-sigpro-app/
|
||||
├── index.html
|
||||
├── main.js
|
||||
├── components/
|
||||
│ ├── Button.js
|
||||
│ ├── TodoList.js
|
||||
│ └── TodoItem.js
|
||||
├── pages/
|
||||
│ ├── HomePage.js
|
||||
│ └── AboutPage.js
|
||||
└── utils/
|
||||
└── helpers.js
|
||||
```
|
||||
|
||||
Example `main.js`:
|
||||
```javascript
|
||||
import { $, html } from 'sigpro';
|
||||
import HomePage from './pages/HomePage.js';
|
||||
|
||||
// Mount your app
|
||||
document.body.appendChild(HomePage());
|
||||
```
|
||||
|
||||
## 🎓 Summary
|
||||
|
||||
You've learned:
|
||||
- ✅ How to install SigPro
|
||||
- ✅ Core concepts: signals, effects, and reactive rendering
|
||||
- ✅ Built a complete todo app
|
||||
- ✅ Key patterns and best practices
|
||||
- ✅ How to structure larger applications
|
||||
|
||||
**Remember:** SigPro embraces the web platform. You're writing vanilla JavaScript with superpowers—no compilation, no lock-in, just clean, maintainable code that will work for years to come.
|
||||
|
||||
> "Stop fighting the platform. Start building with it."
|
||||
|
||||
Happy coding! 🎉
|
||||
@@ -1,135 +1,78 @@
|
||||
# Why SigPro? ❓
|
||||
# Why SigPro?
|
||||
|
||||
After years of building applications with React, Vue, and Svelte—investing countless hours mastering their unique mental models, build tools, and update cycles—I kept circling back to the same realization: no matter how sophisticated the framework, it all eventually compiles down to HTML, CSS, and vanilla JavaScript. The web platform has evolved tremendously, yet many libraries continue to reinvent the wheel, creating parallel universes with their own rules, their own syntaxes, and their own steep learning curves.
|
||||
After years of building applications with React, Vue, and Svelte—investing countless hours mastering unique mental models, proprietary syntaxes, and complex build tools—we reached a realization: the web platform has evolved, but frameworks have become layers of abstraction that often move us further away from the browser.
|
||||
|
||||
**SigPro is my answer to a simple question:** Why fight the platform when we can embrace it?
|
||||
**SigPro** is the answer to a simple question: **Why fight the platform when we can embrace it?**
|
||||
|
||||
## 🌐 The Web Platform Is Finally Ready
|
||||
## The Modern Web is Ready
|
||||
|
||||
Modern browsers now offer powerful primitives that make true reactivity possible without virtual DOM diffing, without compilers, and without lock-in:
|
||||
SigPro bypasses the overhead of the Virtual DOM and heavy compilers by using modern browser primitives. It treats the DOM as a first-class citizen, not as a side effect of a state change.
|
||||
|
||||
| Browser Primitive | What It Enables |
|
||||
|-------------------|-----------------|
|
||||
| **Custom Elements** | Create reusable components with native browser APIs |
|
||||
| **Shadow DOM** | Encapsulate styles and markup without preprocessors |
|
||||
| **CSS Custom Properties** | Dynamic theming without CSS-in-JS |
|
||||
| **Microtask Queues** | Efficient update batching without complex scheduling |
|
||||
| :--- | :--- |
|
||||
| **Closures & Proxies** | Automatic dependency tracking without heavy overhead. |
|
||||
| **ES Modules** | Native modularity and lazy loading without complex bundlers. |
|
||||
| **Direct DOM APIs** | Surgical updates that are faster than any reconciliation algorithm. |
|
||||
| **Microtask Queues** | Batching updates efficiently to ensure 60fps performance. |
|
||||
|
||||
## 🎯 The SigPro Philosophy
|
||||
---
|
||||
|
||||
SigPro strips away the complexity, delivering a reactive programming model that feels familiar but stays remarkably close to vanilla JS:
|
||||
## The SigPro Philosophy
|
||||
|
||||
- **No JSX transformations** - Just template literals
|
||||
- **No template compilers** - The browser parses your HTML
|
||||
- **No proprietary syntax to learn** - Just functions and signals
|
||||
- **No build step required** - Works directly in the browser
|
||||
SigPro strips away the complexity, delivering a reactive programming model that feels like a framework but stays remarkably close to Vanilla JS:
|
||||
|
||||
* **No JSX transformations** – Pure JavaScript functions.
|
||||
* **No Virtual DOM** – Direct, fine-grained DOM manipulation.
|
||||
* **No proprietary syntax** – If you know JS, you know SigPro.
|
||||
* **Zero Build Step Required** – It can run directly in the browser via ESM.
|
||||
|
||||
```javascript
|
||||
// Just vanilla JavaScript with signals
|
||||
import { $, html } from 'sigpro';
|
||||
// Pure, Atomic, Reactive.
|
||||
const $count = $(0);
|
||||
|
||||
const count = $(0);
|
||||
|
||||
document.body.appendChild(html`
|
||||
<div>
|
||||
<p>Count: ${count}</p>
|
||||
<button @click=${() => count(c => c + 1)}>
|
||||
Increment
|
||||
</button>
|
||||
</div>
|
||||
`);
|
||||
const Counter = () => div([
|
||||
p(["Count: ", $count]),
|
||||
button({ onclick: () => $count(c => c + 1) }, "Increment")
|
||||
]);
|
||||
```
|
||||
|
||||
## 📊 Comparative
|
||||
---
|
||||
|
||||
| Metric | SigPro | Solid | Svelte | Vue | React |
|
||||
|--------|--------|-------|--------|-----|-------|
|
||||
| **Bundle Size** (gzip) | 🥇 **5.2KB** | 🥈 15KB | 🥉 16.6KB | 20.4KB | 43.9KB |
|
||||
| **Time to Interactive** | 🥇 **0.8s** | 🥈 1.3s | 🥉 1.4s | 1.6s | 2.3s |
|
||||
| **Initial Render** (ms) | 🥇 **124ms** | 🥈 198ms | 🥉 287ms | 298ms | 452ms |
|
||||
| **Update Performance** (ms) | 🥇 **4ms** | 🥈 5ms | 🥈 5ms | 🥉 7ms | 18ms |
|
||||
| **Dependencies** | 🥇 **0** | 🥇 **0** | 🥇 **0** | 🥈 2 | 🥉 5 |
|
||||
| **Compilation Required** | 🥇 **No** | 🥇 **No** | 🥈 Yes | 🥇 **No** | 🥇 **No** |
|
||||
| **Browser Native** | 🥇 **Yes** | 🥈 Partial | 🥉 Partial | 🥉 Partial | No |
|
||||
| **Framework Lock-in** | 🥇 **None** | 🥈 Medium | 🥉 High | 🥈 Medium | 🥉 High |
|
||||
| **Longevity** (standards-based) | 🥇 **10+ years** | 🥈 5 years | 🥉 3 years | 🥈 5 years | 🥈 5 years |
|
||||
## Performance Comparison
|
||||
|
||||
SigPro isn't just lighter; it's architecturally faster because it skips the "diffing" phase entirely.
|
||||
|
||||
| Metric | SigPro | SolidJS | Svelte | Vue | React |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **Bundle Size (gzip)** | 🥇 **< 2KB** | 🥈 7KB | 🥉 16KB | 20KB | 45KB |
|
||||
| **Architecture** | **Atomic** | **Atomic** | **Compiled** | **V-DOM** | **V-DOM** |
|
||||
| **Initial Render** | 🥇 **Fastest** | 🥈 Fast | 🥉 Fast | Average | Slow |
|
||||
| **Update Perf** | 🥇 **Surgical** | 🥇 Surgical | 🥈 Fast | 🥉 Average | Slow |
|
||||
| **Dependencies** | 🥇 **0** | 🥇 0 | 🥇 0 | 🥈 2 | 🥉 5+ |
|
||||
| **Build Step** | 🥇 **Optional** | 🥈 Required | 🥈 Required | 🥇 Optional | 🥈 Required |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Core Principles
|
||||
|
||||
SigPro is built on four fundamental principles:
|
||||
SigPro is built on four fundamental pillars:
|
||||
|
||||
### 📡 **True Reactivity**
|
||||
Automatic dependency tracking with no manual subscriptions. When a signal changes, only the exact DOM nodes that depend on it update—surgically, efficiently, instantly.
|
||||
### 📡 Atomic Reactivity
|
||||
Automatic dependency tracking with no manual subscriptions. When a signal changes, only the **exact** text nodes or attributes that depend on it update—instantly and surgically.
|
||||
|
||||
### ⚡ **Surgical Updates**
|
||||
No virtual DOM diffing. No tree reconciliation. Just direct DOM updates where and when needed. The result is predictable performance that scales with your content, not your component count.
|
||||
### ⚡ Surgical DOM Updates
|
||||
No Virtual DOM diffing. No tree reconciliation. We don't guess what changed; we know exactly where the update needs to happen. Performance scales with your data, not the size of your component tree.
|
||||
|
||||
### 🧩 **Web Standards**
|
||||
Built on Custom Elements, not a custom rendering engine. Your components are real web components that work in any framework—or none at all.
|
||||
### 🧩 Plugin-First Architecture
|
||||
The core is a tiny, powerful engine. Need Routing? Fetching? Global UI? Just plug it in. This keeps your production bundles "pay-only-for-what-you-use."
|
||||
|
||||
### 🔬 **Predictable**
|
||||
No magic, just signals and effects. What you see is what you get. The debugging experience is straightforward because there's no framework layer between your code and the browser.
|
||||
### 🔬 Predictable & Transparent
|
||||
There is no "magic" hidden in a black-box compiler. What you write is what the browser executes. Debugging is straightforward because there is no framework layer between your code and the DevTools.
|
||||
|
||||
## 🎨 The Development Experience
|
||||
---
|
||||
|
||||
```javascript
|
||||
// With VS Code + lit-html extension, you get:
|
||||
// ✅ Syntax highlighting
|
||||
// ✅ Color previews
|
||||
// ✅ Auto-formatting
|
||||
// ✅ IntelliSense
|
||||
> "SigPro returns the joy of web development by making the browser the hero again."
|
||||
|
||||
html`
|
||||
<div style="color: #ff4444; background: linear-gradient(45deg, blue, green)">
|
||||
<h1>Beautiful highlighted template</h1>
|
||||
</div>
|
||||
`
|
||||
```
|
||||
|
||||
## ⏱️ Built for the Long Term
|
||||
|
||||
What emerged is a library that proves we've reached a turning point: the web is finally mature enough that we don't need to abstract it anymore. We can build reactive, component-based applications using virtually pure JavaScript, leveraging the platform's latest advances instead of working against them.
|
||||
|
||||
**The result isn't just smaller bundles or faster rendering—it's code that will still run 10 years from now, in any browser, without maintenance.**
|
||||
|
||||
## 📈 The Verdict
|
||||
|
||||
While other frameworks build parallel universes with proprietary syntax and compilation steps, SigPro embraces the web platform. SigPro isn't just another framework—it's a return to fundamentals, showing that the dream of simple, powerful reactivity is now achievable with the tools browsers give us out of the box.
|
||||
|
||||
> *"Stop fighting the platform. Start building with it."*
|
||||
|
||||
## 🚀 Ready to Start?
|
||||
|
||||
[Get Started with SigPro](/guide/getting-started) • [View on GitHub](https://github.com/natxocc/sigpro) • [npm Package](https://www.npmjs.com/package/sigpro)
|
||||
|
||||
<style>
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 2rem 0;
|
||||
padding: 1.5rem;
|
||||
background: linear-gradient(135deg, var(--vp-c-brand-soft) 0%, transparent 100%);
|
||||
border-radius: 12px;
|
||||
font-size: 1.2rem;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,84 +1,96 @@
|
||||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "SigPro"
|
||||
text: "Reactivity for the Web Platform"
|
||||
tagline: A minimalist reactive library for building web interfaces with signals, effects, and native web components. No compilation, no virtual DOM, just pure JavaScript and intelligent reactivity.
|
||||
name: SigPro
|
||||
text: Atomic Unified Reactive Engine
|
||||
tagline: Fine-grained reactivity, built-in routing, and modular plugins. All under 2KB.
|
||||
image:
|
||||
src: /logo.svg
|
||||
alt: SigPro
|
||||
src: /logo.png
|
||||
alt: SigPro Logo
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Get Started
|
||||
link: /guide/getting-started
|
||||
- theme: alt
|
||||
text: View on GitHub
|
||||
link: https://git.natxocc.com/sigpro/
|
||||
|
||||
features:
|
||||
- title: ⚡ 3KB gzipped
|
||||
details: Minimal footprint with maximum impact. No heavy dependencies, just pure reactivity.
|
||||
- title: 🎯 Native Web Components
|
||||
details: Built on Custom Elements and Shadow DOM. Leverage the platform, don't fight it.
|
||||
- title: 🔄 Signal-based Reactivity
|
||||
details: Fine-grained updates without virtual DOM diffing. Just intelligent, automatic reactivity.
|
||||
- title: Atomic Reactivity
|
||||
details: Powered by Signals. Only updates what changes. No Virtual DOM overhead, no heavy re-renders.
|
||||
- title: Zero Dependencies
|
||||
details: Written in pure Vanilla JS. Maximum performance with the smallest footprint possible.
|
||||
- title: Modular Ecosystem
|
||||
details: Official plugins for UI components, dynamic Routing, Fetch, and Storage. Load only what you need.
|
||||
---
|
||||
|
||||
<div class="custom-container">
|
||||
<p class="npm-stats">
|
||||
<img src="https://badge.fury.io/js/sigpro.svg" alt="npm version">
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/sigpro" alt="bundle size">
|
||||
<img src="https://img.shields.io/npm/l/sigpro" alt="license">
|
||||
</p>
|
||||
</div>
|
||||
## Why SigPro?
|
||||
|
||||
<div class="verdict-quote">
|
||||
<p><strong>"Stop fighting the platform. Start building with it."</strong></p>
|
||||
</div>
|
||||
SigPro isn't just another framework; it's a high-performance engine. It strips away the complexity of massive bundles and returns to the essence of the web, enhanced with reactive superpowers.
|
||||
|
||||
<style>
|
||||
.npm-stats {
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
### The Core in Action
|
||||
|
||||
.npm-stats img {
|
||||
margin: 0 0.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
```javascript
|
||||
import { $ } from 'sigpro2';
|
||||
|
||||
.custom-container {
|
||||
max-width: 1152px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
}
|
||||
// A reactive state Signal
|
||||
const $count = $(0);
|
||||
|
||||
.verdict-quote {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
margin: 3rem 0;
|
||||
padding: 2rem;
|
||||
background: linear-gradient(135deg, var(--vp-c-brand-soft) 0%, transparent 100%);
|
||||
border-radius: 12px;
|
||||
}
|
||||
// A Computed signal that updates automatically
|
||||
const $double = $(() => $count() * 2);
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
// UI that breathes with your data
|
||||
const Counter = () => div([
|
||||
h1(["Count: ", $count]),
|
||||
p(["Double: ", $double]),
|
||||
button({ onclick: () => $count(c => c + 1) }, "Increment")
|
||||
]);
|
||||
|
||||
th {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
$.mount(Counter);
|
||||
```
|
||||
|
||||
td {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
---
|
||||
|
||||
tr:hover {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
}
|
||||
</style>
|
||||
### Key Features
|
||||
|
||||
#### ⚡️ Fine-Grained Reactivity
|
||||
Unlike frameworks that diff complex trees (V-DOM), SigPro binds your signals directly to real DOM text nodes and attributes. If the data changes, the node changes. Period.
|
||||
|
||||
#### 🔌 Polymorphic Plugin System
|
||||
Extend core capabilities in a single line. Add global UI helpers, routing, or state persistence seamlessly.
|
||||
```javascript
|
||||
import { UI, Router } from 'sigpro/plugins';
|
||||
$.plugin([UI, Router]);
|
||||
```
|
||||
|
||||
#### 📂 File-Based Routing
|
||||
With our dedicated Vite plugin, manage your routes simply by creating files in `src/pages/`. It supports native **Lazy Loading** out of the box for lightning-fast initial loads.
|
||||
|
||||
---
|
||||
|
||||
### Quick Install
|
||||
|
||||
::: code-group
|
||||
```bash [npm]
|
||||
npm install sigpro
|
||||
```
|
||||
```bash [pnpm]
|
||||
pnpm add sigpro
|
||||
```
|
||||
```bash [yarn]
|
||||
yarn add sigpro
|
||||
```
|
||||
```bash [bun]
|
||||
bun add sigpro
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Community & Support
|
||||
SigPro is an open-source project. Whether you want to contribute, report a bug, or just talk about reactivity, join us on our official repository.
|
||||
|
||||
```
|
||||
Built with ❤️ by NatxoCC
|
||||
```
|
||||
|
||||
107
src/docs/plugins/core.debug.md
Normal file
107
src/docs/plugins/core.debug.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Development Tool: `_debug`
|
||||
|
||||
The **Debug Plugin** is a lightweight reactive listener. Once attached to a signal or a computed function, it automatically monitors changes, compares values, and formats the output in the browser console.
|
||||
|
||||
## 1. Core Features
|
||||
|
||||
* **Reactive Tracking:** Automatically logs whenever the tracked signal updates.
|
||||
* **Visual Grouping:** Uses styled console groups to keep your dev tools organized.
|
||||
* **Object Inspection:** Automatically uses `console.table()` when the signal contains an object or array.
|
||||
* **Efficient Comparison:** Uses `Object.is` to prevent redundant logging if the value hasn't actually changed.
|
||||
|
||||
---
|
||||
|
||||
## 2. Installation
|
||||
|
||||
To use `_debug`, you only need the SigPro core. Register the plugin in your `main.js`. You can conditionally load it so it only runs during development.
|
||||
|
||||
```javascript
|
||||
import { $ } from 'sigpro';
|
||||
import { Debug } from 'sigpro/plugins';
|
||||
|
||||
// Only load Debug in development mode
|
||||
const plugins = [];
|
||||
if (import.meta.env.DEV) plugins.push(Debug);
|
||||
|
||||
$.plugin(plugins).then(() => {
|
||||
import('./App.js').then(app => $.mount(app.default));
|
||||
});
|
||||
```
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install sigpro
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add sigpro
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add sigpro
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add sigpro
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 3. Basic Usage
|
||||
|
||||
Call `_debug` anywhere in your component. It stays active in the background, watching the signal's lifecycle.
|
||||
|
||||
```javascript
|
||||
export default () => {
|
||||
const $count = $(0);
|
||||
const $user = $({ name: "Guest", role: "Viewer" });
|
||||
|
||||
// Start tracking
|
||||
_debug($count, "Main Counter");
|
||||
_debug($user, "User Session");
|
||||
|
||||
return div([
|
||||
button({ onclick: () => $count(c => c + 1) }, "Increment"),
|
||||
button({ onclick: () => $user({ name: "Admin", role: "Super" }) }, "Promote")
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Console Output Breakdown
|
||||
|
||||
When a signal changes, the console displays a structured block:
|
||||
|
||||
1. **Header:** A styled badge with the name (e.g., `SigPro Debug: Main Counter`).
|
||||
2. **Previous Value:** The value before the update (in red).
|
||||
3. **Current Value:** The new value (in green).
|
||||
4. **Table View:** If the value is an object, a formatted table appears automatically.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. Debugging Computed Values
|
||||
|
||||
You can also debug **computed functions** to see exactly when derived state is recalculated.
|
||||
|
||||
```javascript
|
||||
const $price = $(100);
|
||||
const $tax = $(0.21);
|
||||
const $total = $(() => $price() * (1 + $tax()));
|
||||
|
||||
// Monitor the result of the calculation
|
||||
_debug($total, "Final Invoice Total");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Why use `_debug`?
|
||||
|
||||
1. **Clean Logic:** No need to scatter `console.log` inside your reactive functions.
|
||||
2. **State History:** Instantly see the "Before" and "After" of any user action.
|
||||
3. **No-Noise:** It only logs when a real change occurs, keeping the console clean.
|
||||
4. **Deep Inspection:** The automatic `console.table` makes debugging large API responses much faster.
|
||||
|
||||
80
src/docs/plugins/core.fetch.md
Normal file
80
src/docs/plugins/core.fetch.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Data Fetching: `_fetch`
|
||||
|
||||
The **Fetch Plugin** provides a reactive wrapper around the native browser Fetch API. Instead of managing complex `async/await` flows within your UI, `_fetch` returns a "Reactive Tripod" (Data, Loading, and Error) that your components can listen to automatically.
|
||||
|
||||
## 1. Core Concept
|
||||
|
||||
When you call `_fetch`, it returns three signals immediately. Your UI declares how to react to these signals as they change from their initial state to the final response.
|
||||
|
||||
* **`$data`**: Initialized as `null`. Automatically holds the JSON response on success.
|
||||
* **`$loading`**: Initialized as `true`. Flips to `false` once the request settles.
|
||||
* **`$error`**: Initialized as `null`. Holds the error message if the request fails.
|
||||
|
||||
---
|
||||
|
||||
## 2. Installation
|
||||
|
||||
Register the `Fetch` plugin in your `main.js`. By convention, we load it alongside the UI and Router to have the full SigPro ecosystem ready.
|
||||
|
||||
```javascript
|
||||
import { $ } from 'sigpro';
|
||||
import { Fetch } from 'sigpro/plugins';
|
||||
|
||||
$.plugin([Fetch]).then(() => {
|
||||
// Now _fetch() is available globally
|
||||
import('./App.js').then(app => $.mount(app.default));
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 3. Basic Usage
|
||||
|
||||
Use `_fetch` inside your component to get live updates. The UI updates surgically whenever a signal changes.
|
||||
|
||||
```javascript
|
||||
export default () => {
|
||||
const { $data, $loading, $error } = _fetch('https://api.github.com/users/octocat');
|
||||
|
||||
return div({ class: 'p-6 flex flex-col gap-4' }, [
|
||||
h1("Profile Details"),
|
||||
|
||||
// 1. Loading State (using SigPro UI button)
|
||||
() => $loading() && _button({ $loading: true }, "Fetching..."),
|
||||
|
||||
// 2. Error State
|
||||
() => $error() && div({ class: 'alert alert-error' }, $error()),
|
||||
|
||||
// 3. Success State
|
||||
() => $data() && div({ class: 'card bg-base-200 p-4' }, [
|
||||
img({ src: $data().avatar_url, class: 'w-16 rounded-full' }),
|
||||
h2($data().name),
|
||||
p($data().bio)
|
||||
])
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Advanced Configuration
|
||||
|
||||
`_fetch` accepts the same `RequestInit` options as the standard `fetch()` (methods, headers, body, etc.).
|
||||
|
||||
```javascript
|
||||
const { $data, $loading } = _fetch('/api/v1/update', {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status: 'active' })
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Why use `_fetch` instead of native Fetch?
|
||||
|
||||
1. **Declarative UI**: You define the "Loading", "Error", and "Success" templates once, and they swap automatically.
|
||||
2. **No `useEffect` required**: Since SigPro is natively reactive, you don't need lifecycle hooks to trigger re-renders; the signals handle it.
|
||||
3. **Consistency**: It follows the same `_prefix` pattern as the rest of the official plugin ecosystem.
|
||||
4. **Automatic JSON Parsing**: It assumes JSON by default and handles 404/500 errors by populating the `$error` signal.
|
||||
110
src/docs/plugins/core.router.md
Normal file
110
src/docs/plugins/core.router.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Navigation Plugin: `Router`
|
||||
|
||||
The SigPro Router handles URL changes via hashes (`#`) and maps them to components. It supports dynamic parameters (like `:id`) and asynchronous loading for heavy pages.
|
||||
|
||||
## 1. Core Features
|
||||
|
||||
* **Hash-based:** Works everywhere without special server configuration.
|
||||
* **Lazy Loading:** Pages are only downloaded when the user visits the route.
|
||||
* **Reactive:** The view updates automatically when the hash changes.
|
||||
* **Dynamic Routes:** Supports paths like `/user/:id`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Installation
|
||||
|
||||
The Router is usually included in the official plugins package.
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add -d tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 3. Setting Up Routes
|
||||
|
||||
In your `App.js` (or a dedicated routes file), define your navigation map.
|
||||
|
||||
```javascript
|
||||
const routes = [
|
||||
{ path: '/', component: () => h1("Home Page") },
|
||||
{
|
||||
path: '/admin',
|
||||
// Lazy Loading: This file is only fetched when needed
|
||||
component: () => import('./pages/Admin.js')
|
||||
},
|
||||
{ path: '/user/:id', component: (params) => h2(`User ID: ${params.id}`) },
|
||||
{ path: '*', component: () => div("404 - Page Not Found") }
|
||||
];
|
||||
|
||||
export default () => div([
|
||||
_navbar({ title: "My App" }),
|
||||
_router(routes) // The router is now a global tag
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Navigation (`_router.go`)
|
||||
|
||||
To move between pages programmatically (e.g., inside an `onclick` event), use the global `_router.go` helper.
|
||||
|
||||
```javascript
|
||||
_button({
|
||||
onclick: () => _router.go('/admin')
|
||||
}, "Go to Admin")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. How it Works (Under the Hood)
|
||||
|
||||
The router tracks the `window.location.hash` and uses a reactive signal to trigger a re-render of the specific area where `_router(routes)` is placed.
|
||||
|
||||
1. **Match:** It filters your route array to find the best fit.
|
||||
2. **Resolve:** * If it's a standard function, it executes it immediately.
|
||||
* If it's a **Promise** (via `import()`), it shows a loading state and swaps the content once the module arrives.
|
||||
3. **Inject:** It replaces the previous DOM node with the new page content surgically.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. Integration with UI Components
|
||||
|
||||
Since you are using the **UI Plugin**, you can easily create active states in your navigation menus by checking the current hash.
|
||||
|
||||
```javascript
|
||||
// Example of a reactive sidebar menu
|
||||
_menu({
|
||||
items: [
|
||||
{
|
||||
label: 'Dashboard',
|
||||
active: () => window.location.hash === '#/',
|
||||
onclick: () => _router.go('/')
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
active: () => window.location.hash === '#/settings',
|
||||
onclick: () => _router.go('/settings')
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
106
src/docs/plugins/core.storage.md
Normal file
106
src/docs/plugins/core.storage.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Persistence Tool: `_storage`
|
||||
|
||||
The Storage plugin synchronizes a signal with a specific key in your browser's `localStorage`. It handles both the **initial hydration** (loading data when the app starts) and **automatic saving** whenever the signal's value changes.
|
||||
|
||||
## 1. Core Concept
|
||||
|
||||
When you "attach" a signal to `_storage`, two things happen:
|
||||
1. **Hydration:** The plugin checks if the key already exists in `localStorage`. If it does, it parses the JSON and updates the signal immediately.
|
||||
2. **Reactive Sync:** It creates a reactive watcher that stringifies and saves the signal's value to the disk every time it is updated.
|
||||
|
||||
---
|
||||
|
||||
## 2. Installation
|
||||
|
||||
Register the `Storage` plugin in your `main.js`. Since this is a logic-only plugin, it doesn't require any CSS or UI dependencies.
|
||||
|
||||
```javascript
|
||||
import { $ } from 'sigpro';
|
||||
import { Storage } from 'sigpro/plugins';
|
||||
|
||||
$.plugin(Storage).then(() => {
|
||||
import('./App.js').then(app => $.mount(app.default));
|
||||
});
|
||||
```
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install sigpro
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add sigpro
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add sigpro
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add sigpro
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 3. Basic Usage
|
||||
|
||||
You can wrap any signal with `_storage`. It is common practice to do this right after creating the signal.
|
||||
|
||||
```javascript
|
||||
export default () => {
|
||||
// 1. Create a signal with a default value
|
||||
const $theme = $( 'light' );
|
||||
|
||||
// 2. Persist it. If 'user_theme' exists in localStorage,
|
||||
// $theme will be updated to that value instantly.
|
||||
_storage($theme, 'user_theme');
|
||||
|
||||
return div({ class: () => `app-${$theme()}` }, [
|
||||
h1(`Current Theme: ${$theme()}`),
|
||||
button({
|
||||
onclick: () => $theme(t => t === 'light' ? 'dark' : 'light')
|
||||
}, "Toggle Theme")
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Complex Data (Objects & Arrays)
|
||||
|
||||
Since the plugin uses `JSON.parse` and `JSON.stringify` internally, it works perfectly with complex state structures.
|
||||
|
||||
```javascript
|
||||
const $settings = $({
|
||||
notifications: true,
|
||||
fontSize: 16
|
||||
});
|
||||
|
||||
// Automatically saves the whole object whenever any property changes
|
||||
_storage($settings, 'app_settings');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Why use `_storage`?
|
||||
|
||||
1. **Zero Boilerplate:** You don't need to manually write `localStorage.getItem` or `setItem` logic inside your components.
|
||||
2. **Chaining:** Because `_storage` returns the signal, you can persist it inline.
|
||||
3. **Error Resilience:** It includes a built-in `try/catch` block to prevent your app from crashing if the stored JSON is corrupted.
|
||||
4. **Surgical Persistence:** Only the signals you explicitly mark for storage are saved, keeping your `localStorage` clean.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. Pro Tip: Combining with Debug
|
||||
|
||||
You can chain plugins to create a fully monitored and persistent state:
|
||||
|
||||
```javascript
|
||||
const $score = _storage($(0), 'high_score');
|
||||
|
||||
// Now it's saved to disk AND logged to console on every change
|
||||
_debug($score, "Game Score");
|
||||
```
|
||||
147
src/docs/plugins/core.ui.md
Normal file
147
src/docs/plugins/core.ui.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Official UI Plugin: `UI`
|
||||
|
||||
The **SigPro UI** plugin is a high-level component library built on top of the reactive core. It leverages **Tailwind CSS v4** for utility styling and **daisyUI v5** for semantic components.
|
||||
|
||||
## 1. Prerequisites & Installation
|
||||
|
||||
To use these components, you must install the styling engine. SigPro UI provides the logic, but Tailwind and daisyUI provide the visuals.
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add -D tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add -d tailwindcss @tailwindcss/vite daisyui@next
|
||||
```
|
||||
:::
|
||||
|
||||
Would you like to continue with the **Router.md** documentation now?
|
||||
|
||||
### CSS Configuration (`app.css`)
|
||||
In Tailwind v4, configuration is handled directly in your CSS. Create a `src/app.css` file:
|
||||
|
||||
```css
|
||||
/* src/app.css */
|
||||
@import "tailwindcss";
|
||||
|
||||
/* Import daisyUI v5 as a Tailwind v4 plugin */
|
||||
@plugin "daisyui";
|
||||
|
||||
/* Optional: Configure themes */
|
||||
@custom-variant dark (&:where(.dark, [data-theme="dark"], [data-theme="dark"] *)));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Initialization
|
||||
|
||||
You must import your CSS and register the `UI` plugin in your entry point. This populates the global scope with reactive component helpers (prefixed with `_`).
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import './app.css';
|
||||
import { $ } from 'sigpro';
|
||||
import { UI } from 'sigpro/plugins';
|
||||
|
||||
$.plugin(UI).then(() => {
|
||||
// Global components like _button and _input are now ready
|
||||
import('./App.js').then(app => $.mount(app.default));
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Core Component Tags (`_tags`)
|
||||
|
||||
SigPro UI components are more than just HTML; they are **Reactive Functional Components** that manage complex states (loading, errors, accessibility) automatically.
|
||||
|
||||
### A. Action Components (`_button`)
|
||||
The `_button` automatically handles spinners and disabled states based on signals.
|
||||
|
||||
| Property | Type | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| **`$loading`** | `signal` | If true, shows a spinner and disables the button. |
|
||||
| **`$disabled`**| `signal` | Manually disables the button (logic-bound). |
|
||||
| **`icon`** | `node/str`| Prepends an icon to the text. |
|
||||
| **`badge`** | `string` | Appends a small badge to the button. |
|
||||
|
||||
```javascript
|
||||
_button({
|
||||
$loading: $isSaving,
|
||||
icon: '💾',
|
||||
class: 'btn-primary'
|
||||
}, "Save Data")
|
||||
```
|
||||
|
||||
### B. High-Density Forms (`_input`, `_select`, `_checkbox`)
|
||||
These components wrap the raw input in a `fieldset` with integrated labels and tooltips.
|
||||
|
||||
* **`label`**: Field title displayed above the input.
|
||||
* **`tip`**: Displays a `?` badge that shows a tooltip on hover.
|
||||
* **`$error`**: A signal that, when populated, turns the input red and displays the message.
|
||||
* **`$value`**: **Two-way binding**. Updates the signal on input and the input on signal change.
|
||||
|
||||
```javascript
|
||||
_input({
|
||||
label: "Username",
|
||||
tip: "Choose a unique name",
|
||||
$value: $name,
|
||||
$error: $nameError
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Complex UI Patterns
|
||||
|
||||
### Reactive Modals (`_modal`)
|
||||
The `_modal` is surgically mounted. If the `$open` signal is `false`, the component is completely removed from the DOM, optimizing performance.
|
||||
|
||||
```javascript
|
||||
const $showModal = $(false);
|
||||
|
||||
_modal({ $open: $showModal, title: "Alert" }, [
|
||||
p("Are you sure you want to proceed?"),
|
||||
_button({ onclick: () => doAction() }, "Confirm")
|
||||
])
|
||||
```
|
||||
|
||||
### Navigation & Layout (`_tabs`, `_drawer`, `_navbar`)
|
||||
Designed to work seamlessly with the **Router**.
|
||||
|
||||
| Component | Key Logic |
|
||||
| :--- | :--- |
|
||||
| **`_tabs`** | Accepts an `active` property (signal or function) to highlight the current tab. |
|
||||
| **`_drawer`** | A responsive sidebar that toggles via an ID or an `$open` signal. |
|
||||
| **`_navbar`** | Standard top bar with shadow and glass effect support. |
|
||||
| **`_menu`** | Vertical navigation list with active state support. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Summary Table: UI Globals
|
||||
|
||||
Once `$.plugin(UI)` is active, these tags are available project-wide:
|
||||
|
||||
| Tag | Category | Use Case |
|
||||
| :--- | :--- | :--- |
|
||||
| `_fieldset` | Layout | Grouping related inputs with a `legend`. |
|
||||
| `_accordion`| Content | Collapsible sections (FAQs). |
|
||||
| `_badge` | Feedback | Status indicators (Success, Warning). |
|
||||
| `_tooltip` | Feedback | Descriptive text on hover. |
|
||||
| `_range` | Input | Reactive slider for numerical values. |
|
||||
|
||||
---
|
||||
|
||||
### What's next?
|
||||
With the UI ready and styled via **Tailwind v4**, we can move to the **Router.md**. We will explain how to link `_tabs` and `_menu` to different URL paths for a full SPA experience.
|
||||
|
||||
**Would you like to start with the Router configuration?**
|
||||
123
src/docs/plugins/custom.md
Normal file
123
src/docs/plugins/custom.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Creating Custom Plugins
|
||||
|
||||
There are two main ways to expose a plugin's functionality: **Static/Manual Imports** (cleaner for large projects) or **Global/Automatic Window Injection** (easier for quick scripts and global helpers).
|
||||
|
||||
## 1. The Anatomy of a Plugin
|
||||
|
||||
A plugin is a standard JavaScript function. By convention, if a plugin adds a global helper or component, it should be prefixed with an underscore (`_`).
|
||||
|
||||
```javascript
|
||||
// plugins/my-utils.js
|
||||
export const MyUtils = ($) => {
|
||||
|
||||
// 1. Attach to the SigPro instance
|
||||
$.capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||
|
||||
// 2. Attach to the Window (Global access)
|
||||
window._hello = (name) => div(`Hello, ${$.capitalize(name)}!`);
|
||||
|
||||
// 3. You can also return values if needed
|
||||
return { version: '1.0.0' };
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Integration Strategies
|
||||
|
||||
### Option A: Manual Import (Recommended)
|
||||
This approach keeps your global namespace clean. You import the logic only where you need it, but the plugin still initializes the core `$` extensions.
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import { $ } from 'sigpro';
|
||||
import { MyUtils } from './plugins/my-utils.js';
|
||||
|
||||
$.plugin(MyUtils);
|
||||
|
||||
// App.js
|
||||
export default () => {
|
||||
const name = "sigpro";
|
||||
// $.capitalize was added by the plugin
|
||||
return h1($.capitalize(name));
|
||||
};
|
||||
```
|
||||
|
||||
### Option B: Automatic Window Injection
|
||||
If your plugin defines global tags (like `_button` or `_hello`), you should attach them to the `window` object inside the plugin function. This makes them available everywhere without imports.
|
||||
|
||||
```javascript
|
||||
// plugins/theme.js
|
||||
export const Theme = ($) => {
|
||||
const $dark = $(false);
|
||||
|
||||
window._themeToggle = () => button({
|
||||
onclick: () => $dark(v => !v),
|
||||
class: () => $dark() ? 'bg-black text-white' : 'bg-white text-black'
|
||||
}, "Toggle Mode");
|
||||
};
|
||||
|
||||
// main.js
|
||||
$.plugin(Theme).then(() => {
|
||||
// _themeToggle is now a global function
|
||||
$.mount(App);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Asynchronous Plugins
|
||||
If your plugin needs to load external data or scripts before the app starts, make it `async`. SigPro will wait for it.
|
||||
|
||||
```javascript
|
||||
export const ConfigLoader = async ($) => {
|
||||
const res = await fetch('/config.json');
|
||||
const config = await res.json();
|
||||
|
||||
$.config = config; // Attach loaded config to SigPro
|
||||
};
|
||||
|
||||
// Usage
|
||||
$.plugin(ConfigLoader).then(() => {
|
||||
console.log("Config loaded:", $.config);
|
||||
$.mount(App);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Best Practices for Plugin Authors
|
||||
|
||||
| Rule | Description |
|
||||
| :--- | :--- |
|
||||
| **Prefixing** | Use `_` for UI components (`_modal`) and `$.` for logic (`$.fetch`). |
|
||||
| **Idempotency** | Ensure calling `$.plugin(MyPlugin)` twice doesn't break the app. |
|
||||
| **Encapsulation** | Use the `$` instance passed as an argument rather than importing it again inside the plugin. |
|
||||
| **Reactivity** | Always use `$(...)` for internal state so the app stays reactive. |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. Installation
|
||||
|
||||
Custom plugins don't require extra packages, but ensure your build tool (Vite/Bun) is configured to handle the module imports.
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install sigpro
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add sigpro
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add sigpro
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add sigpro
|
||||
```
|
||||
:::
|
||||
|
||||
101
src/docs/plugins/quick.md
Normal file
101
src/docs/plugins/quick.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Extending SigPro: `$.plugin`
|
||||
|
||||
The plugin system is the engine's way of growing. It allows you to inject new functionality directly into the `$` object or load external resources.
|
||||
|
||||
## 1. How Plugins Work
|
||||
|
||||
A plugin in **SigPro** is simply a function that receives the core instance. When you run `$.plugin(MyPlugin)`, the engine hands over the `$` object so the plugin can attach new methods or register global tags (like `div()`, `span()`, etc.).
|
||||
|
||||
### Functional Plugin Example
|
||||
```javascript
|
||||
// A plugin that adds a simple logger to any signal
|
||||
const Logger = ($) => {
|
||||
$.watch = (target, label = "Log") => {
|
||||
$(() => console.log(`[${label}]:`, target()));
|
||||
};
|
||||
};
|
||||
|
||||
// Activation
|
||||
$.plugin(Logger);
|
||||
const $count = $(0);
|
||||
$.watch($count, "Counter"); // Now available globally via $
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Initialization Patterns
|
||||
|
||||
Since plugins often set up global variables (like the HTML tags), the order of initialization is critical. Here are the two ways to start your app:
|
||||
|
||||
### Option A: The "Safe" Async Start (Recommended)
|
||||
This is the most robust way. It ensures all global tags (`div`, `button`, etc.) are created **before** your App code is even read by the browser.
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import { $ } from 'sigpro';
|
||||
import { UI, Router } from 'sigpro/plugins';
|
||||
|
||||
// 1. Load plugins first
|
||||
$.plugin([UI, Router]).then(() => {
|
||||
|
||||
// 2. Import your app only after the environment is ready
|
||||
import('./App.js').then(appFile => {
|
||||
const MyApp = appFile.default;
|
||||
$.mount(MyApp, '#app');
|
||||
});
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### Option B: Static Start (No Global Tags)
|
||||
Use this only if you prefer **not** to use global tags and want to use `$.html` directly in your components. This allows for standard static imports.
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import { $ } from 'sigpro';
|
||||
import { UI } from 'sigpro/plugins';
|
||||
import MyApp from './App.js'; // Static import works here
|
||||
|
||||
$.plugin(UI);
|
||||
$.mount(MyApp, '#app');
|
||||
```
|
||||
> **Warning:** In this mode, if `App.js` uses `div()` instead of `$.html('div')`, it will throw a `ReferenceError`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Resource Plugins (External Scripts)
|
||||
|
||||
You can pass a **URL** or an **Array of URLs**. SigPro will inject them as `<script>` tags and return a Promise that resolves when the scripts are fully loaded and executed.
|
||||
|
||||
```javascript
|
||||
// Loading external libraries as plugins
|
||||
await $.plugin([
|
||||
'https://cdn.jsdelivr.net/npm/chart.js',
|
||||
'https://cdn.example.com/custom-ui-lib.js'
|
||||
]);
|
||||
|
||||
console.log("External resources are ready to use!");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Polymorphic Loading Reference
|
||||
|
||||
The `$.plugin` method adapts to whatever you throw at it:
|
||||
|
||||
| Input Type | Action | Behavior |
|
||||
| :--- | :--- | :--- |
|
||||
| **Function** | Executes `fn($)` | Synchronous / Immediate |
|
||||
| **String (URL)** | Injects `<script src="...">` | Asynchronous (Returns Promise) |
|
||||
| **Array** | Processes each item in the list | Returns Promise if any item is Async |
|
||||
|
||||
---
|
||||
|
||||
## 💡 Pro Tip: Why the `.then()`?
|
||||
|
||||
Using `$.plugin([...]).then(...)` is like giving your app a "Pre-flight Check". It guarantees that:
|
||||
1. All reactive methods are attached.
|
||||
2. Global HTML tags are defined.
|
||||
3. External libraries (like Chart.js) are loaded.
|
||||
4. **The result:** Your components are cleaner, smaller, and error-free.
|
||||
|
||||
@@ -1,287 +1,33 @@
|
||||
# Vite Plugin: Automatic File-based Routing 🚦
|
||||
# Vite Plugin: File-based Routing
|
||||
|
||||
SigPro provides an optional Vite plugin that automatically generates routes based on your file structure. No configuration needed - just create pages and they're instantly available with the correct paths.
|
||||
The `sigproRouter` plugin for Vite automates route generation by scanning your pages directory. It creates a **virtual module** that you can import directly into your code, eliminating the need to maintain a manual routes array.
|
||||
|
||||
## Why Use This Plugin?
|
||||
## 1. Project Structure
|
||||
|
||||
While SigPro's router works perfectly with manually defined routes, this plugin:
|
||||
- **Eliminates boilerplate** - No need to write route configurations
|
||||
- **Enforces conventions** - Consistent URL structure across your app
|
||||
- **Supports dynamic routes** - Use `[param]` syntax for parameters
|
||||
- **Automatic code-splitting** - Each page becomes a separate chunk
|
||||
- **Type-safe** (with JSDoc) - Routes follow your file structure
|
||||
To use the plugin, organize your files within the `src/pages` directory. The folder hierarchy directly determines your application's URL structure.
|
||||
|
||||
## Installation
|
||||
|
||||
The plugin is included with SigPro, but you need to add it to your Vite config:
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
import { defineConfig } from 'vite';
|
||||
import { sigproRouter } from 'sigpro';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sigproRouter()]
|
||||
});
|
||||
```text
|
||||
my-sigpro-app/
|
||||
├── src/
|
||||
│ ├── pages/
|
||||
│ │ ├── index.js → #/
|
||||
│ │ ├── about.js → #/about
|
||||
│ │ ├── users/
|
||||
│ │ │ └── [id].js → #/users/:id
|
||||
│ │ └── blog/
|
||||
│ │ ├── index.js → #/blog
|
||||
│ │ └── [slug].js → #/blog/:slug
|
||||
│ ├── App.js (Optional App Shell)
|
||||
│ └── main.js (Entry Point)
|
||||
├── vite.config.js
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## How It Works
|
||||
---
|
||||
|
||||
The plugin scans your `src/pages` directory and automatically generates routes based on the file structure:
|
||||
## 2. Setup & Configuration
|
||||
|
||||
```
|
||||
src/pages/
|
||||
├── index.js → '/'
|
||||
├── about.js → '/about'
|
||||
├── blog/
|
||||
│ ├── index.js → '/blog'
|
||||
│ └── [slug].js → '/blog/:slug'
|
||||
└── users/
|
||||
├── [id].js → '/users/:id'
|
||||
└── [id]/edit.js → '/users/:id/edit'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Enable the Plugin
|
||||
|
||||
Add the plugin to your Vite config as shown above.
|
||||
|
||||
### 2. Import the Generated Routes
|
||||
|
||||
Once you have the generated routes, using them with the router is straightforward:
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import { $, html } from 'sigpro';
|
||||
import { routes } from 'virtual:sigpro-routes';
|
||||
|
||||
// Simple usage
|
||||
const router = $.router(routes);
|
||||
document.body.appendChild(router);
|
||||
```
|
||||
|
||||
Or directly in your template:
|
||||
|
||||
```javascript
|
||||
// app.js
|
||||
import { $, html } from 'sigpro';
|
||||
import { routes } from 'virtual:sigpro-routes';
|
||||
|
||||
const App = () => html`
|
||||
<div class="app">
|
||||
<header>
|
||||
<h1>My Application</h1>
|
||||
</header>
|
||||
|
||||
<main class="p-4 flex flex-col gap-4 mx-auto w-full">
|
||||
<div class="p-4 bg-base-100 rounded-box shadow-sm">
|
||||
${$.router(routes)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(App());
|
||||
```
|
||||
|
||||
This approach keeps your template clean and lets the router handle all the page rendering automatically.
|
||||
|
||||
### 3. Create Pages
|
||||
|
||||
```javascript
|
||||
// src/pages/index.js
|
||||
import { $, html } from 'sigpro';
|
||||
|
||||
export default () => {
|
||||
return html`
|
||||
<div>
|
||||
<h1>Home Page</h1>
|
||||
<a href="#/about">About</a>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
```javascript
|
||||
// src/pages/users/[id].js
|
||||
import { $, html } from 'sigpro';
|
||||
|
||||
export default (params) => {
|
||||
const userId = params.id;
|
||||
|
||||
return html`
|
||||
<div>
|
||||
<h1>User Profile: ${userId}</h1>
|
||||
<a href="#/users/${userId}/edit">Edit</a>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
## 📋 File-to-Route Mapping
|
||||
|
||||
### Static Routes
|
||||
|
||||
| File Path | Generated Route |
|
||||
|-----------|-----------------|
|
||||
| `src/pages/index.js` | `/` |
|
||||
| `src/pages/about.js` | `/about` |
|
||||
| `src/pages/contact/index.js` | `/contact` |
|
||||
| `src/pages/blog/post.js` | `/blog/post` |
|
||||
|
||||
### Dynamic Routes
|
||||
|
||||
| File Path | Generated Route | Example URL |
|
||||
|-----------|-----------------|-------------|
|
||||
| `src/pages/users/[id].js` | `/users/:id` | `/users/42` |
|
||||
| `src/pages/blog/[slug].js` | `/blog/:slug` | `/blog/hello-world` |
|
||||
| `src/pages/users/[id]/posts/[pid].js` | `/users/:id/posts/:pid` | `/users/42/posts/123` |
|
||||
|
||||
### Nested Routes
|
||||
|
||||
| File Path | Generated Route | Notes |
|
||||
|-----------|-----------------|-------|
|
||||
| `src/pages/settings/index.js` | `/settings` | Index page |
|
||||
| `src/pages/settings/profile.js` | `/settings/profile` | Sub-page |
|
||||
| `src/pages/settings/security.js` | `/settings/security` | Sub-page |
|
||||
| `src/pages/settings/[section].js` | `/settings/:section` | Dynamic section |
|
||||
|
||||
## 🎯 Advanced Examples
|
||||
|
||||
### Blog with Posts
|
||||
|
||||
```javascript
|
||||
// src/pages/blog/index.js - Lists all posts
|
||||
export default () => {
|
||||
const posts = $([]);
|
||||
|
||||
$.effect(() => {
|
||||
fetch('/api/posts')
|
||||
.then(res => res.json())
|
||||
.then(data => posts(data));
|
||||
});
|
||||
|
||||
return html`
|
||||
<div>
|
||||
<h1>Blog</h1>
|
||||
${posts().map(post => html`
|
||||
<article>
|
||||
<h2><a href="#/blog/${post.slug}">${post.title}</a></h2>
|
||||
<p>${post.excerpt}</p>
|
||||
</article>
|
||||
`)}
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
```javascript
|
||||
// src/pages/blog/[slug].js - Single post
|
||||
export default (params) => {
|
||||
const post = $(null);
|
||||
const slug = params.slug;
|
||||
|
||||
$.effect(() => {
|
||||
fetch(`/api/posts/${slug}`)
|
||||
.then(res => res.json())
|
||||
.then(data => post(data));
|
||||
});
|
||||
|
||||
return html`
|
||||
<div>
|
||||
<a href="#/blog">← Back to blog</a>
|
||||
${() => post() ? html`
|
||||
<article>
|
||||
<h1>${post().title}</h1>
|
||||
<div>${post().content}</div>
|
||||
</article>
|
||||
` : html`<div>Loading...</div>`}
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
### Dashboard with Nested Sections
|
||||
|
||||
```javascript
|
||||
// src/pages/dashboard/index.js
|
||||
export default () => {
|
||||
return html`
|
||||
<div class="dashboard">
|
||||
<nav>
|
||||
<a href="#/dashboard">Overview</a>
|
||||
<a href="#/dashboard/analytics">Analytics</a>
|
||||
<a href="#/dashboard/settings">Settings</a>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Dashboard Overview</h1>
|
||||
<!-- Overview content -->
|
||||
</main>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
```javascript
|
||||
// src/pages/dashboard/analytics.js
|
||||
export default () => {
|
||||
return html`
|
||||
<div class="dashboard">
|
||||
<nav>
|
||||
<a href="#/dashboard">Overview</a>
|
||||
<a href="#/dashboard/analytics">Analytics</a>
|
||||
<a href="#/dashboard/settings">Settings</a>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>Analytics</h1>
|
||||
<!-- Analytics content -->
|
||||
</main>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
### E-commerce Product Routes
|
||||
|
||||
```javascript
|
||||
// src/pages/products/[category]/[id].js
|
||||
export default (params) => {
|
||||
const { category, id } = params;
|
||||
const product = $(null);
|
||||
|
||||
$.effect(() => {
|
||||
fetch(`/api/products/${category}/${id}`)
|
||||
.then(res => res.json())
|
||||
.then(data => product(data));
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="product-page">
|
||||
<nav class="breadcrumbs">
|
||||
<a href="#/products">Products</a> >
|
||||
<a href="#/products/${category}">${category}</a> >
|
||||
<span>${id}</span>
|
||||
</nav>
|
||||
|
||||
${() => product() ? html`
|
||||
<div class="product">
|
||||
<h1>${product().name}</h1>
|
||||
<p class="price">$${product().price}</p>
|
||||
<p>${product().description}</p>
|
||||
<button @click=${() => addToCart(product())}>
|
||||
Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
` : html`<div>Loading...</div>`}
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
## 🔧 Configuration Options
|
||||
|
||||
The plugin accepts an optional configuration object:
|
||||
Add the plugin to your `vite.config.js`.
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
@@ -289,135 +35,90 @@ import { defineConfig } from 'vite';
|
||||
import { sigproRouter } from 'sigpro/vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
sigproRouter({
|
||||
pagesDir: 'src/pages', // Default: 'src/pages'
|
||||
extensions: ['.js', '.jsx'], // Default: ['.js', '.jsx']
|
||||
exclude: ['**/_*', '**/components/**'] // Glob patterns to exclude
|
||||
})
|
||||
]
|
||||
plugins: [sigproRouter()]
|
||||
});
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `pagesDir` | `string` | `'src/pages'` | Directory containing your pages |
|
||||
| `extensions` | `string[]` | `['.js', '.jsx']` | File extensions to include |
|
||||
| `exclude` | `string[]` | `[]` | Glob patterns to exclude |
|
||||
|
||||
## 🎯 Route Priority
|
||||
|
||||
The plugin automatically sorts routes to ensure correct matching:
|
||||
|
||||
1. **Static routes** take precedence over dynamic ones
|
||||
2. **More specific routes** (deeper paths) come first
|
||||
3. **Alphabetical order** for routes at the same level
|
||||
|
||||
Example sorting:
|
||||
```
|
||||
/users/new (static, specific)
|
||||
/users/[id]/edit (dynamic, deeper)
|
||||
/users/[id] (dynamic, shallower)
|
||||
/users/profile (static, shallower)
|
||||
```
|
||||
|
||||
## 📦 Output Example
|
||||
|
||||
When you import `virtual:sigpro-routes`, you get:
|
||||
|
||||
```javascript
|
||||
// Generated module
|
||||
import Page_0 from '/src/pages/index.js';
|
||||
import Page_1 from '/src/pages/about.js';
|
||||
import Page_2 from '/src/pages/blog/index.js';
|
||||
import Page_3 from '/src/pages/blog/[slug].js';
|
||||
import Page_4 from '/src/pages/users/[id].js';
|
||||
import Page_5 from '/src/pages/users/[id]/edit.js';
|
||||
|
||||
export const routes = [
|
||||
{ path: '/', component: Page_0 },
|
||||
{ path: '/about', component: Page_1 },
|
||||
{ path: '/blog', component: Page_2 },
|
||||
{ path: '/blog/:slug', component: Page_3 },
|
||||
{ path: '/users/:id', component: Page_4 },
|
||||
{ path: '/users/:id/edit', component: Page_5 },
|
||||
];
|
||||
```
|
||||
|
||||
## 🚀 Performance Benefits
|
||||
|
||||
- **Automatic code splitting** - Each page becomes a separate chunk
|
||||
- **Lazy loading ready** - Import pages dynamically
|
||||
- **Tree shaking** - Only used routes are included
|
||||
|
||||
```javascript
|
||||
// With dynamic imports (automatic with Vite)
|
||||
const routes = [
|
||||
{ path: '/', component: () => import('./pages/index.js') },
|
||||
{ path: '/about', component: () => import('./pages/about.js') },
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
## 💡 Pro Tips
|
||||
|
||||
### 1. Group Related Pages
|
||||
|
||||
```
|
||||
src/pages/
|
||||
├── dashboard/
|
||||
│ ├── index.js
|
||||
│ ├── analytics.js
|
||||
│ └── settings.js
|
||||
└── dashboard.js # ❌ Don't mix with folder
|
||||
```
|
||||
|
||||
### 2. Use Index Files for Clean URLs
|
||||
|
||||
```
|
||||
✅ Good:
|
||||
pages/blog/index.js → /blog
|
||||
pages/blog/post.js → /blog/post
|
||||
|
||||
❌ Avoid:
|
||||
pages/blog.js → /blog (conflicts with folder)
|
||||
```
|
||||
|
||||
### 3. Private Components
|
||||
|
||||
Prefix with underscore to exclude from routing:
|
||||
|
||||
```
|
||||
src/pages/
|
||||
├── index.js
|
||||
├── about.js
|
||||
└── _components/ # ❌ Not scanned
|
||||
└── Header.js
|
||||
```
|
||||
|
||||
### 4. Layout Components
|
||||
|
||||
Create a layout wrapper in your main entry:
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import { $, html } from 'sigpro';
|
||||
import { routes } from 'virtual:sigpro-routes';
|
||||
|
||||
// Wrap all routes with layout
|
||||
const routesWithLayout = routes.map(route => ({
|
||||
...route,
|
||||
component: (params) => Layout(route.component(params))
|
||||
}));
|
||||
|
||||
const router = $.router(routesWithLayout);
|
||||
document.body.appendChild(router);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **Note:** This plugin is completely optional. You can always define routes manually if you prefer. The plugin just saves you from writing boilerplate route configurations.
|
||||
## 3. Implementation
|
||||
|
||||
> **Pro Tip:** The plugin works great with hot module replacement (HMR) - add a new page and it's instantly available in your dev server without restarting!
|
||||
You can implement the router either directly in your entry point or inside an App component to support persistent layouts (like a navbar that doesn't re-render).
|
||||
|
||||
### Option A: Direct in `main.js`
|
||||
Best for simple apps where the router occupies the entire viewport.
|
||||
|
||||
```javascript
|
||||
// src/main.js
|
||||
import { $ } from 'sigpro';
|
||||
import { Router } from 'sigpro/plugins';
|
||||
import { routes } from 'virtual:sigpro-routes';
|
||||
|
||||
$.plugin(Router).then(() => {
|
||||
$.mount(_router(routes), '#app');
|
||||
});
|
||||
```
|
||||
|
||||
### Option B: Inside `App.js` (With Layout)
|
||||
Recommended for apps with a fixed Sidebar or Navbar.
|
||||
|
||||
```javascript
|
||||
// src/main.js
|
||||
import { $ } from 'sigpro';
|
||||
import { Router } from 'sigpro/plugins';
|
||||
|
||||
$.plugin(Router).then(() => {
|
||||
import('./App.js').then(app => $.mount(app.default, '#app'));
|
||||
});
|
||||
|
||||
// src/App.js
|
||||
import { routes } from 'virtual:sigpro-routes';
|
||||
|
||||
export default () => {
|
||||
return div({ class: 'layout' }, [
|
||||
header([
|
||||
h1("SigPro App"),
|
||||
nav([
|
||||
a({ href: '#/' }, "Home"),
|
||||
a({ href: '#/blog' }, "Blog")
|
||||
])
|
||||
]),
|
||||
// The router only swaps the content inside this <main> tag
|
||||
main(_router(routes))
|
||||
]);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Route Mapping Reference
|
||||
|
||||
| File Path | Generated Route | Logic |
|
||||
| :--- | :--- | :--- |
|
||||
| `index.js` | `/` | Home page |
|
||||
| `about.js` | `/about` | Static path |
|
||||
| `[id].js` | `/:id` | Dynamic parameter |
|
||||
| `blog/index.js` | `/blog` | Folder index |
|
||||
| `_utils.js` | *Ignored* | Files starting with `_` are skipped |
|
||||
|
||||
---
|
||||
|
||||
## 5. Installation
|
||||
|
||||
::: code-group
|
||||
```bash [NPM]
|
||||
npm install sigpro
|
||||
```
|
||||
|
||||
```bash [PNPM]
|
||||
pnpm add sigpro
|
||||
```
|
||||
|
||||
```bash [Yarn]
|
||||
yarn add sigpro
|
||||
```
|
||||
|
||||
```bash [Bun]
|
||||
bun add sigpro
|
||||
```
|
||||
:::
|
||||
|
||||
Reference in New Issue
Block a user