reconsile cdrl error
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { createSignal, onCleanup, onMount, Show, For, JSXElement } from "solid-js";
|
||||
import { createSignal, createMemo, onCleanup, onMount, Show, For, JSXElement } from "solid-js";
|
||||
|
||||
// CrmTabGroup / CrmSubTabGroup — drop-in, behaviourally identical siblings of
|
||||
// TabGroup (same props, storageKey syncing, controlled/uncontrolled index) with
|
||||
@@ -26,13 +26,15 @@ function resolveCrmBadge(badge: number | undefined): number | undefined {
|
||||
|
||||
// Shared active-index state: mirrors TabGroup exactly (localStorage persistence,
|
||||
// cross-component sync via synthetic storage events, optional controlled index).
|
||||
function createCrmTabState(props: CrmTabGroupProps) {
|
||||
// Takes the memoized `items` accessor (not props.items) so length checks read the
|
||||
// same single evaluation the render does — see the createMemo note in CrmTabGroup.
|
||||
function createCrmTabState(props: CrmTabGroupProps, items: () => CrmTabItem[]) {
|
||||
const getInitialIndex = () => {
|
||||
if (props.storageKey) {
|
||||
const stored = localStorage.getItem(props.storageKey);
|
||||
if (stored !== null) {
|
||||
const parsed = parseInt(stored, 10);
|
||||
if (!isNaN(parsed) && parsed >= 0 && parsed < props.items.length) {
|
||||
if (!isNaN(parsed) && parsed >= 0 && parsed < items().length) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,7 @@ function createCrmTabState(props: CrmTabGroupProps) {
|
||||
const handler = (e: StorageEvent) => {
|
||||
if (e.key !== props.storageKey || e.newValue == null) return;
|
||||
const n = parseInt(e.newValue, 10);
|
||||
if (!isNaN(n) && n >= 0 && n < props.items.length && n !== _activeIndex()) {
|
||||
if (!isNaN(n) && n >= 0 && n < items().length && n !== _activeIndex()) {
|
||||
_setActiveIndex(n);
|
||||
props.onTabChange && props.onTabChange(n);
|
||||
}
|
||||
@@ -103,11 +105,19 @@ const CRM_TAB_ACTIVE = "border-x border-t-2 border-t-sky-700 text-primary";
|
||||
const CRM_TAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-primary text-white rounded-full";
|
||||
|
||||
export function CrmTabGroup(props: CrmTabGroupProps) {
|
||||
const { activeIndex, setActiveIndex } = createCrmTabState(props);
|
||||
// Memoize props.items: callers pass items={[{content: <Comp/>}]} where each
|
||||
// `content` is eager JSX, and Solid re-evaluates a `prop={expr}` getter on every
|
||||
// read. Reading props.items directly (in the button For, the content For, and the
|
||||
// length checks reached from the onclick handler) would re-run createComponent on
|
||||
// every tab's content each time — and the read inside setActiveIndex happens outside
|
||||
// the render owner, so those rebuilt components lose their provider context
|
||||
// (useToast/useModal throw). The memo evaluates the tree once, inside this owner.
|
||||
const items = createMemo(() => props.items);
|
||||
const { activeIndex, setActiveIndex } = createCrmTabState(props, items);
|
||||
|
||||
return <div class="w-full">
|
||||
<div class={CRM_TAB_ROW}>
|
||||
<For each={props.items}>{(item: CrmTabItem, index: () => number) => (
|
||||
<For each={items()}>{(item: CrmTabItem, index: () => number) => (
|
||||
<button type="button" onclick={() => setActiveIndex(index())} class={CRM_TAB_BASE + " " + (index() === activeIndex() ? CRM_TAB_ACTIVE : CRM_TAB_INACTIVE)}>
|
||||
{item.title}
|
||||
<Show when={(() => {
|
||||
@@ -121,7 +131,7 @@ export function CrmTabGroup(props: CrmTabGroupProps) {
|
||||
<div class="flex-1 border-b border-line-strong"></div>
|
||||
</div>
|
||||
<div>
|
||||
{crmTabContent(props.items, activeIndex)}
|
||||
{crmTabContent(items(), activeIndex)}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
@@ -141,12 +151,14 @@ const CRM_SUBTAB_INACTIVE = "bg-surface text-ink-soft hover:bg-surface-raised ho
|
||||
const CRM_SUBTAB_BADGE = "inline-flex items-center justify-center min-w-5 h-5 px-1 text-xs font-semibold bg-black/10 text-current rounded-full";
|
||||
|
||||
export function CrmSubTabGroup(props: CrmTabGroupProps) {
|
||||
const { activeIndex, setActiveIndex } = createCrmTabState(props);
|
||||
// See CrmTabGroup: memoize eager `content` JSX so it's built once, in-owner.
|
||||
const items = createMemo(() => props.items);
|
||||
const { activeIndex, setActiveIndex } = createCrmTabState(props, items);
|
||||
|
||||
return <div class="w-full pt-3">
|
||||
<div class={CRM_SUBTAB_WRAP}>
|
||||
<div class={CRM_SUBTAB_GROUP}>
|
||||
<For each={props.items}>{(item: CrmTabItem, index: () => number) => (
|
||||
<For each={items()}>{(item: CrmTabItem, index: () => number) => (
|
||||
<button type="button" onclick={() => setActiveIndex(index())} class={CRM_SUBTAB_BASE + (index() > 0 ? " " + CRM_SUBTAB_DIVIDER : "") + " " + (index() === activeIndex() ? CRM_SUBTAB_ACTIVE : CRM_SUBTAB_INACTIVE)}>
|
||||
{item.title}
|
||||
<Show when={(() => {
|
||||
@@ -160,7 +172,7 @@ export function CrmSubTabGroup(props: CrmTabGroupProps) {
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-3">
|
||||
{crmTabContent(props.items, activeIndex)}
|
||||
{crmTabContent(items(), activeIndex)}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user