anentrypoint-design 0.0.304 → 0.0.306
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app-shell.css +12 -8
- package/dist/247420.css +138 -8
- package/dist/247420.js +15 -15
- package/package.json +1 -1
- package/src/components/editor-primitives.js +144 -11
- package/src/components.js +3 -0
- package/src/kits/os/shell.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.306",
|
|
4
4
|
"description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/247420.js",
|
|
@@ -223,6 +223,45 @@ export function useMediaQuery(query) {
|
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Grid / GridItem — 24-column responsive layout primitive (screen-real-estate
|
|
228
|
+
// density: dense multi-column panels without a hand-rolled grid-template-
|
|
229
|
+
// columns per consumer). Column-span props are integers 1-24 (or `true` for
|
|
230
|
+
// full-width/auto-grow, or `0` to hide at that breakpoint) evaluated at four
|
|
231
|
+
// tiers mirroring BP_SM/MD/LG/XL (480/768/1024/1440) via media queries in
|
|
232
|
+
// editor-primitives.css — no JS-side matchMedia needed, CSS custom
|
|
233
|
+
// properties + @media do the layout work so it degrades gracefully with
|
|
234
|
+
// SSR/no-hydration. Grid itself is a flex row wrapper; GridItem computes
|
|
235
|
+
// flex-basis/max-width from its span at each tier.
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
export function Grid({ gap, justify, align, children, key } = {}) {
|
|
238
|
+
const style = [
|
|
239
|
+
gap != null ? `gap:${typeof gap === 'number' ? gap + 'px' : gap}` : '',
|
|
240
|
+
justify ? `justify-content:${justify}` : '',
|
|
241
|
+
align ? `align-items:${align}` : '',
|
|
242
|
+
].filter(Boolean).join(';');
|
|
243
|
+
return h('div', { key, class: 'ds-ep-grid', style: style || null }, children);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function gridSpanStyle(prefix, val) {
|
|
247
|
+
if (val === undefined) return '';
|
|
248
|
+
if (val === true) return `--${prefix}-basis:100%;--${prefix}-grow:1;--${prefix}-display:inherit;`;
|
|
249
|
+
if (val === 0) return `--${prefix}-display:none;`;
|
|
250
|
+
const pct = Math.max(0, Math.min(100, (100 / 24) * val));
|
|
251
|
+
return `--${prefix}-basis:${pct}%;--${prefix}-grow:0;--${prefix}-display:inherit;`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function GridItem({ xs, sm, md, lg, xl, children, key } = {}) {
|
|
255
|
+
const style = [
|
|
256
|
+
gridSpanStyle('xs', xs),
|
|
257
|
+
gridSpanStyle('sm', sm),
|
|
258
|
+
gridSpanStyle('md', md),
|
|
259
|
+
gridSpanStyle('lg', lg),
|
|
260
|
+
gridSpanStyle('xl', xl),
|
|
261
|
+
].join('');
|
|
262
|
+
return h('div', { key, class: 'ds-ep-grid-item', style: style || null }, children);
|
|
263
|
+
}
|
|
264
|
+
|
|
226
265
|
// ---------------------------------------------------------------------------
|
|
227
266
|
// FocusTrap — wraps subtree, traps Tab/Shift+Tab. Mount/unmount lifecycle is
|
|
228
267
|
// managed via DOM-level keydown listener attached when first focused.
|
|
@@ -592,25 +631,69 @@ export function toast({ message, kind = 'info', duration = 3000 } = {}) {
|
|
|
592
631
|
// gm-pager. page is 1-indexed; pageCount<=1 disables both buttons (no
|
|
593
632
|
// divide-by-zero, no dead-end enabled control). total (optional) renders an
|
|
594
633
|
// item-count suffix ("42 items") alongside the page label.
|
|
634
|
+
//
|
|
635
|
+
// numbered=true switches to a compact numbered-button row (screen-real-estate
|
|
636
|
+
// dense mode) instead of the prev/next label: always shows first, last, the
|
|
637
|
+
// current page, and up to `siblingCount` neighbors either side, collapsing
|
|
638
|
+
// gaps into an ellipsis span. Falls back to prev/next automatically when
|
|
639
|
+
// pageCount<=1. The prev/next contract (default) is untouched.
|
|
595
640
|
// ---------------------------------------------------------------------------
|
|
596
|
-
|
|
641
|
+
function buildPageRange(count, page, siblingCount) {
|
|
642
|
+
const limit = siblingCount * 2 + 3; // first + last + current + siblings
|
|
643
|
+
if (count <= limit) return Array.from({ length: count }, (_, i) => i + 1);
|
|
644
|
+
const pages = new Set([1, count, page]);
|
|
645
|
+
for (let i = 1; i <= siblingCount; i++) {
|
|
646
|
+
pages.add(page - i);
|
|
647
|
+
pages.add(page + i);
|
|
648
|
+
}
|
|
649
|
+
const sorted = [...pages].filter((p) => p >= 1 && p <= count).sort((a, b) => a - b);
|
|
650
|
+
const result = [];
|
|
651
|
+
let prev = null;
|
|
652
|
+
for (const p of sorted) {
|
|
653
|
+
if (prev !== null && p - prev > 1) result.push('...');
|
|
654
|
+
result.push(p);
|
|
655
|
+
prev = p;
|
|
656
|
+
}
|
|
657
|
+
return result;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
export function Pager({ page = 1, pageCount = 1, onPage, total, itemLabel = 'items', numbered = false, siblingCount = 1 } = {}) {
|
|
597
661
|
const safeCount = Math.max(1, pageCount || 1);
|
|
598
662
|
const safePage = Math.min(Math.max(1, page || 1), safeCount);
|
|
599
663
|
const atStart = safePage <= 1;
|
|
600
664
|
const atEnd = safePage >= safeCount;
|
|
665
|
+
const prevBtn = h('button', {
|
|
666
|
+
type: 'button', class: 'ds-ep-pager-btn', disabled: atStart ? 'disabled' : null,
|
|
667
|
+
'aria-label': 'previous page',
|
|
668
|
+
onclick: () => { if (!atStart && onPage) onPage(safePage - 1); },
|
|
669
|
+
}, '<-');
|
|
670
|
+
const nextBtn = h('button', {
|
|
671
|
+
type: 'button', class: 'ds-ep-pager-btn', disabled: atEnd ? 'disabled' : null,
|
|
672
|
+
'aria-label': 'next page',
|
|
673
|
+
onclick: () => { if (!atEnd && onPage) onPage(safePage + 1); },
|
|
674
|
+
}, '->');
|
|
675
|
+
if (numbered) {
|
|
676
|
+
const range = buildPageRange(safeCount, safePage, Math.max(1, siblingCount || 1));
|
|
677
|
+
return h('div', { class: 'ds-ep-pager ds-ep-pager-numbered', role: 'group', 'aria-label': 'pagination' },
|
|
678
|
+
prevBtn,
|
|
679
|
+
...range.map((p, i) => p === '...'
|
|
680
|
+
? h('span', { key: 'ellipsis-' + i, class: 'ds-ep-pager-ellipsis' }, '...')
|
|
681
|
+
: h('button', {
|
|
682
|
+
key: 'p' + p, type: 'button',
|
|
683
|
+
class: 'ds-ep-pager-num' + (p === safePage ? ' is-current' : ''),
|
|
684
|
+
'aria-current': p === safePage ? 'page' : null,
|
|
685
|
+
'aria-label': 'page ' + p,
|
|
686
|
+
onclick: () => { if (p !== safePage && onPage) onPage(p); },
|
|
687
|
+
}, String(p))),
|
|
688
|
+
nextBtn,
|
|
689
|
+
total != null ? h('span', { class: 'ds-ep-pager-total' }, total + ' ' + itemLabel) : null
|
|
690
|
+
);
|
|
691
|
+
}
|
|
601
692
|
return h('div', { class: 'ds-ep-pager', role: 'group', 'aria-label': 'pagination' },
|
|
602
|
-
|
|
603
|
-
type: 'button', class: 'ds-ep-pager-btn', disabled: atStart ? 'disabled' : null,
|
|
604
|
-
'aria-label': 'previous page',
|
|
605
|
-
onclick: () => { if (!atStart && onPage) onPage(safePage - 1); },
|
|
606
|
-
}, '<-'),
|
|
693
|
+
prevBtn,
|
|
607
694
|
h('span', { class: 'ds-ep-pager-label' },
|
|
608
695
|
'page ' + safePage + ' / ' + safeCount + (total != null ? ' (' + total + ' ' + itemLabel + ')' : '')),
|
|
609
|
-
|
|
610
|
-
type: 'button', class: 'ds-ep-pager-btn', disabled: atEnd ? 'disabled' : null,
|
|
611
|
-
'aria-label': 'next page',
|
|
612
|
-
onclick: () => { if (!atEnd && onPage) onPage(safePage + 1); },
|
|
613
|
-
}, '->')
|
|
696
|
+
nextBtn
|
|
614
697
|
);
|
|
615
698
|
}
|
|
616
699
|
|
|
@@ -747,3 +830,53 @@ export function IconButtonGroup({ items = [], value, onChange, dense = false } =
|
|
|
747
830
|
}, it.glyph != null ? it.glyph : it.label))
|
|
748
831
|
);
|
|
749
832
|
}
|
|
833
|
+
|
|
834
|
+
// ---------------------------------------------------------------------------
|
|
835
|
+
// Collapse — progressive-disclosure toggle panel (screen-real-estate
|
|
836
|
+
// density: property inspectors, nested settings, FAQ-style panels).
|
|
837
|
+
// Controlled component: caller owns `expanded` state and passes `onToggle`,
|
|
838
|
+
// same pattern as Drawer/Dialog `open`/`onClose` above — no internal state.
|
|
839
|
+
// ---------------------------------------------------------------------------
|
|
840
|
+
export function Collapse({ title, expanded = false, onToggle, children, key } = {}) {
|
|
841
|
+
return h('div', { key, class: 'ds-ep-collapse' + (expanded ? ' is-expanded' : '') },
|
|
842
|
+
h('button', {
|
|
843
|
+
type: 'button', class: 'ds-ep-collapse-head',
|
|
844
|
+
'aria-expanded': expanded ? 'true' : 'false',
|
|
845
|
+
onclick: () => { if (onToggle) onToggle(!expanded); },
|
|
846
|
+
},
|
|
847
|
+
h('span', { class: 'ds-ep-collapse-chevron' }, expanded ? 'v' : '>'),
|
|
848
|
+
h('span', { class: 'ds-ep-collapse-title' }, title)),
|
|
849
|
+
expanded ? h('div', { class: 'ds-ep-collapse-body' }, children) : null);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// ---------------------------------------------------------------------------
|
|
853
|
+
// CollapseGroup — accordion wrapper enforcing single-open-at-a-time when
|
|
854
|
+
// `accordion=true` (default false — group just lays out children, each
|
|
855
|
+
// Collapse still individually controlled). `openId`/`onOpenChange` drive the
|
|
856
|
+
// accordion; `items` is [{id, title, children}].
|
|
857
|
+
// ---------------------------------------------------------------------------
|
|
858
|
+
export function CollapseGroup({ items = [], openId, onOpenChange, accordion = false, key } = {}) {
|
|
859
|
+
return h('div', { key, class: 'ds-ep-collapse-group' },
|
|
860
|
+
...items.map((it) => Collapse({
|
|
861
|
+
key: it.id,
|
|
862
|
+
title: it.title,
|
|
863
|
+
expanded: accordion ? it.id === openId : Boolean(it.expanded),
|
|
864
|
+
onToggle: (next) => {
|
|
865
|
+
if (!onOpenChange) return;
|
|
866
|
+
if (accordion) onOpenChange(next ? it.id : null);
|
|
867
|
+
else onOpenChange(it.id, next);
|
|
868
|
+
},
|
|
869
|
+
children: it.children,
|
|
870
|
+
})));
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// ---------------------------------------------------------------------------
|
|
874
|
+
// Divider — plain rule, optional centered text label, optional vertical
|
|
875
|
+
// orientation (for segmenting dense panels without a full Section wrapper).
|
|
876
|
+
// ---------------------------------------------------------------------------
|
|
877
|
+
export function Divider({ label, vertical = false, key } = {}) {
|
|
878
|
+
if (vertical) return h('span', { key, class: 'ds-ep-divider ds-ep-divider-vertical', role: 'separator', 'aria-orientation': 'vertical' });
|
|
879
|
+
if (!label) return h('hr', { key, class: 'ds-ep-divider' });
|
|
880
|
+
return h('div', { key, class: 'ds-ep-divider ds-ep-divider-labeled', role: 'separator' },
|
|
881
|
+
h('span', { class: 'ds-ep-divider-label' }, label));
|
|
882
|
+
}
|
package/src/components.js
CHANGED
package/src/kits/os/shell.js
CHANGED
|
Binary file
|