@wwog/react 1.3.5 → 1.3.8

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/README.md CHANGED
@@ -167,7 +167,7 @@ import { Toggle } from "@wwog/react";
167
167
 
168
168
  #### `<ArrayRender>`
169
169
 
170
- Efficiently render array data, supports filtering and custom rendering.
170
+ Efficiently render array data, supports filtering, sorting, and custom rendering. Optimized for performance with minimal loops.
171
171
 
172
172
  ```tsx
173
173
  import { ArrayRender } from "@wwog/react";
@@ -177,16 +177,27 @@ function UserList({ users }) {
177
177
  <ArrayRender
178
178
  items={users}
179
179
  filter={(user) => user.active}
180
+ sort={(a, b) => a.name.localeCompare(b.name)}
180
181
  renderItem={(user, index) => (
181
182
  <div key={user.id}>
182
183
  {index + 1}. {user.name}
183
184
  </div>
184
185
  )}
186
+ renderEmpty={() => <div>No users found</div>}
185
187
  />
186
188
  );
187
189
  }
188
190
  ```
189
191
 
192
+ - `items`: Array of data to render
193
+ - `renderItem`: Function to render each item, receives (item, index) as parameters
194
+ - `filter`: Optional filter function to filter items
195
+ - `sort`: Optional sort function for array sorting, uses standard comparison function (a, b) => number
196
+ - `renderEmpty`: Optional function to render content when array is empty
197
+
198
+ **Performance Note**: When no sorting is needed, filtering is done during the map loop for optimal performance. When sorting is provided, filtering is applied first, then sorting, to minimize operations.
199
+ ```
200
+
190
201
  #### `<Clamp>` (v1.2.14+)
191
202
 
192
203
  > Removed in v1.3.0. The compatibility problem is too big, the desktop web page works well, h5 has a problem.
@@ -458,7 +469,7 @@ You can also use a container wrapper element:
458
469
 
459
470
  - Supports passing in custom breakpoints, defaults to the same breakpoint definitions as TailwindCSS
460
471
 
461
- This hook is implemented based on listening. If you need to use `useScreen` multiple times without changes, it is recommended to use the extended `BreakpointProvider` and `useBreakpoint` to ensure global listening occurs only once.
472
+ This hook is implemented based on listening. If useScreen needs to be used multiple times without changing the passed parameters, it is recommended to wrap Context
462
473
 
463
474
  Development notes: Internally implemented via `mediaQuery`, it does not listen to a specific breakpoint but is optimized to listen only to the previous and next breakpoints of the current breakpoint for better performance.
464
475
 
package/dist/index.d.mts CHANGED
@@ -465,6 +465,8 @@ interface ArrayRenderProps<T> {
465
465
  items: T[];
466
466
  renderItem: (item: T, index: number) => React$1.ReactNode;
467
467
  filter?: (item: T) => boolean;
468
+ renderEmpty?: () => React$1.ReactNode;
469
+ sort?: (a: T, b: T) => number;
468
470
  }
469
471
  declare function ArrayRender<T>(props: ArrayRenderProps<T>): ReactNode;
470
472
 
@@ -716,11 +718,6 @@ type Responsive<T> = T | Partial<Record<BreakpointName, T>>;
716
718
 
717
719
  declare function getCurrentBreakpoint(breakpointDesc: BreakpointDesc, width: number): BreakpointName;
718
720
  declare function useScreen(breakpointDesc?: BreakpointDesc): "base" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
719
- declare function BreakpointProvider({ children, breakpointDesc, }: {
720
- children: React$1.ReactNode;
721
- breakpointDesc?: BreakpointDesc;
722
- }): React$1.JSX.Element;
723
- declare function useBreakpoint(): "base" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
724
721
 
725
- export { ArrayRender, BreakpointProvider, Counter, DateRender, DefBreakpointDesc, False, If, Observer, Pipe, Scope, SizeBox, Styles, Switch, Toggle, True, When, breakpoints, childrenLoop, createExternalState, createStorageState, cx, formatDate, getCurrentBreakpoint, safePromiseTry, useBreakpoint, useControlled, useScreen };
722
+ export { ArrayRender, Counter, DateRender, DefBreakpointDesc, False, If, Observer, Pipe, Scope, SizeBox, Styles, Switch, Toggle, True, When, breakpoints, childrenLoop, createExternalState, createStorageState, cx, formatDate, getCurrentBreakpoint, safePromiseTry, useControlled, useScreen };
726
723
  export type { ArrayRenderProps, BreakpointDesc, BreakpointName, CreateStateListener, CxInput, DateRenderProps, ElseIfProps, ElseProps, ExternalSideEffect, ExternalState, ExternalStateOptions, ExternalWithKernel, FalseProps, IfProps, ObserverProps, PipeProps, Responsive, ScopeProps, StorageStateOptions, StylesDescriptor, StylesProps, StylesType, SwitchCaseProps, SwitchDefaultProps, SwitchProps, ThenProps, ToggleProps, Transform, TrueProps, UseControlledOptions, WhenProps };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import a,{useMemo as g,Fragment as E,Children as V,isValidElement as Z,cloneElement as z,useEffect as w,useState as k,useRef as C,useCallback as U,createContext as G,useContext as q}from"react";function Y(e,n){if(e===void 0)return;let t=0;if(Array.isArray(e)){for(const r of e)if(n(r,t++)===!1)break}else n(e,t)}const K=(e,n)=>e===n,v=e=>a.createElement(a.Fragment,null,e.children);v.displayName="Switch_Case";const N=e=>a.createElement(a.Fragment,null,e.children);N.displayName="Switch_Default";const y=e=>{const{value:n,compare:t=K,children:r,strict:l=!1}=e,o=new Set;let i=null,m=null,d=!1;return Y(r,(s,c)=>{if(!a.isValidElement(s))throw new Error(`Switch Children only accepts valid React elements at index ${c}`);const u=s.type;if(u.displayName===v.displayName){const f=s.props;if(o.has(f.value))throw new Error(`Switch found duplicate Case value at index ${c}: ${JSON.stringify(f.value)}${l?" (detected in strict mode)":""}`);if(o.add(f.value),!i&&t(n,f.value)&&(i=f.children,l===!1))return!1}else if(u.displayName===N.displayName){if(d)throw new Error(`Switch can only have one Default child at index ${c}`);if(d=!0,m=s.props.children,!l&&i)return!1}else throw new Error(`Switch Children only accepts 'Case' or 'Default' elements, found: ${String(u.displayName||u.name||u)} at index ${c}`)}),a.createElement(a.Fragment,null,i??m)};y.displayName="Switch",y.Case=v,y.Default=N,y.createTyped=function(){return{Switch:y,Case:v,Default:N}};const b=e=>a.createElement(a.Fragment,null,e.children),x=({children:e})=>a.createElement(a.Fragment,null,e),M=e=>a.createElement(a.Fragment,null,e.children);b.displayName="If_Then",x.displayName="If_Else",M.displayName="If_ElseIf";const p=({condition:e,children:n})=>{let t=null,r=null;const l=[];if(a.Children.forEach(n,o=>{if(!a.isValidElement(o))throw new Error("If component only accepts valid React elements");const i=o.type;if(i.displayName===b.displayName){if(t)throw new Error("If component can only have one Then child");t=o}else if(i.displayName===M.displayName)l.push(o);else if(i.displayName===x.displayName){if(r)throw new Error("If component can only have one Else child");r=o}else throw new Error(`If component only accepts 'Then', 'ElseIf', or 'Else' elements as children, found: ${String(i.displayName||i.name||i)}`)}),e)return t?a.createElement(a.Fragment,null,t.props.children):null;for(const o of l)if(o.props.condition)return a.createElement(a.Fragment,null,o.props.children);return r?a.createElement(a.Fragment,null,r.props.children):null};p.displayName="If",p.Then=b,p.ElseIf=M,p.Else=x,p.createTyped=function(){return{If:p,Then:b,ElseIf:M,Else:x}};const Q=({condition:e,children:n})=>e?a.createElement(a.Fragment,null,n):null,X=({condition:e,children:n})=>e===!1?a.createElement(a.Fragment,null,n):null,ee=({all:e,any:n,none:t,children:r,fallback:l})=>g(()=>(e&&(n||t)&&console.warn('When: Multiple condition types (all, any, none) provided; "all" takes precedence.'),!!(e&&e.length>0&&e.every(Boolean)||n&&n.length>0&&n.some(Boolean)||t&&t.length>0&&t.every(o=>!o))),[e,n,t])?a.createElement(a.Fragment,null,r):a.createElement(a.Fragment,null,l||null),te=({data:e,transform:n,render:t,fallback:r})=>{const l=g(()=>n.reduce((o,i)=>i(o),e),[e,n]);return l==null?a.createElement(a.Fragment,null,r||null):a.createElement(a.Fragment,null,t(l))},ne=e=>{const{children:n,h:t,w:r,size:l,height:o,width:i,className:m}=e;return a.createElement("div",{style:{width:l||r||i,height:l||t||o,flexShrink:0},className:m},n)},re=({let:e,props:n,children:t,fallback:r})=>{const l=g(()=>typeof e=="function"?e(n):e,[e,n]);return!t||!Object.keys(l).length?a.createElement(a.Fragment,null,r||null):a.createElement(a.Fragment,null,t(l))};function F(...e){const n=new Set;for(const t of e)if(t){if(typeof t=="string")n.add(t);else if(Array.isArray(t))t.forEach(r=>n.add(r));else if(typeof t=="object")for(const[r,l]of Object.entries(t))l&&n.add(r)}return Array.from(n).join(" ")}const oe=e=>typeof e=="object"&&!!e,O=({className:e,children:n,asWrapper:t=!1})=>{if(!n)return null;if(!e)return a.createElement(E,null,n);const r=typeof e=="string"?e:F(...Object.values(e));if(t)return a.createElement(t===!0?"div":t,{className:r},n);if(V.count(n)>1)return console.error("<Styles>: children has more than one child. Please check your code."),a.createElement(E,null,n);if(Z(n)){const l=n;let o=l?.props?.className;return l?.type?.displayName===O.displayName&&oe(o)&&(o=F(...Object.values(o))),z(n,{className:F(r,o)})}return console.error("<Styles>: children is not a valid React element. Please check your code."),a.createElement(E,null,n)};O.displayName="W/Styles";const le=e=>{const{index:n=0,options:t,next:r,render:l}=e;w(()=>{if(t.length<n+1)throw new Error(`Index ${n} is out of bounds for options array of length ${t.length}. Defaulting to first option.`)},[n,t]);const[o,i]=k(n),m=()=>{i(d=>t.length?r?r(d,t):(d+1)%t.length:d)};return l(t[o],m)},ae=({onIntersect:e,threshold:n=.1,root:t=null,rootMargin:r="0px",triggerOnce:l=!1,disabled:o=!1,children:i,className:m,style:d})=>{const s=C(null),c=C(null),u=C(!1);return w(()=>{if(o||!s.current)return;if(!window.IntersectionObserver){console.warn("IntersectionObserver is not supported in this browser");return}const f=s.current,h=D=>{D.forEach(I=>{l&&u.current||(e(I,c.current),l&&(u.current=!0,c.current?.unobserve(f)))})};return c.current=new IntersectionObserver(h,{root:t,rootMargin:r,threshold:n}),c.current.observe(f),()=>{c.current&&c.current.disconnect()}},[e,n,t,r,l,o]),w(()=>{l||(u.current=!1)},[l]),a.createElement("div",{ref:s,className:m,style:d},i)};function se(e){const{items:n,renderItem:t,filter:r}=e;return n?a.createElement(E,null,n.map((l,o)=>r&&!r(l)?null:t(l,o))):(console.error("ArrayRender: items is null"),null)}function ie({source:e,format:n,children:t}){const r=g(()=>{if(e instanceof Date)return e;if(typeof e=="string"||typeof e=="number"){const o=new Date(e);return isNaN(o.getTime())?null:o}return null},[e]),l=g(()=>r?n?n(r):r.toLocaleString():null,[r,n]);return!l||!t?null:a.createElement(a.Fragment,null,t(l))}const ce="onChange",ue="value";function de(e){const{defaultValue:n,onBeforeChange:t,trigger:r=ce,valuePropName:l=ue,props:o}=e,i=Object.prototype.hasOwnProperty.call(o,l),[m,d]=k(n),s=i?o[l]:m,c=g(()=>o[r],[o,r]),u=U(f=>{const h=typeof f=="function"?f(s):f;t&&t(h,s)===!1||(i||d(h),c&&c(h))},[i,t,s,c]);return[s,u]}function fe(e,...n){try{const t=e(...n);return t instanceof Promise?t:Promise.resolve(t)}catch(t){return Promise.reject(t)}}const j=typeof Promise.try=="function"?Promise.try.bind(Promise):fe;function J(e,n={}){let t=typeof e=="function"?e():e;const r=[],{sideEffect:l,transform:o}=n,i=()=>{const s=t;return o?.get?o.get(s):s},m=s=>{const c=t,u=o?.get?o.get(c):c;t=o?.set?o.set(typeof s=="function"?s(u):s):typeof s=="function"?s(u):s,r.forEach(f=>f(t)),l&&j(l,t,c).catch(f=>{console.error("Error in external state side effect, Please do it within side effects:",f)})},d=()=>{const[s,c]=a.useState(t);return a.useEffect(()=>(r.push(c),()=>{const u=r.indexOf(c);u>-1&&r.splice(u,1)}),[]),[o?.get?o.get(s):s,m]};return{get:i,set:m,use:d,useGetter:()=>{const[s]=d();return s},__listeners:r}}function me(e,n,t){const{storageType:r="local",sideEffect:l,transform:o}=t??{},i=r==="local"?localStorage:sessionStorage;let m=n;const d=i.getItem(e);if(d)try{m=JSON.parse(d)}catch(s){console.warn(`Failed to parse ${r}Storage value for key "${e}", using initial state:`,s),m=n}return J(m,{sideEffect:s=>{i.setItem(e,JSON.stringify(s)),l?.(s)},transform:o})}function he(e,n){const t=n||new Date,r=t.getFullYear(),l=t.getMonth()+1,o=t.getDate(),i=t.getHours(),m=t.getMinutes(),d=t.getSeconds(),s=t.getMilliseconds(),c=t.getDay(),u=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],f=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],D=["January","February","March","April","May","June","July","August","September","October","November","December"],I=f[c],T=u[c],A=l-1,_=D[A],$=h[A],L={YY:r.toString().slice(2),YYYY:r.toString(),M:l.toString(),MM:l.toString().padStart(2,"0"),MMM:$,MMMM:_,D:o.toString(),DD:o.toString().padStart(2,"0"),d:c.toString(),dd:T,ddd:T,dddd:I,H:i.toString(),HH:i.toString().padStart(2,"0"),h:(i%12).toString(),hh:(i%12).toString().padStart(2,"0"),m:m.toString(),mm:m.toString().padStart(2,"0"),s:d.toString(),ss:d.toString().padStart(2,"0"),SSS:s.toString().padStart(3,"0"),Z:"+08:00",ZZ:"+0800",A:i<12?"AM":"PM",a:i<12?"am":"pm"};return e.replace(/YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,H=>L[H])}class pe{count=0;next(){return this.count++}}const S=["base","xs","sm","md","lg","xl","2xl","3xl"],B={xs:475,sm:640,md:768,lg:1024,xl:1280,"2xl":1536,"3xl":1920},ge=[...S].reverse();function P(e,n){for(const t of ge){const r=e[t];if(r!==void 0&&!Number.isNaN(r)&&n>=r)return t}return"base"}function W(e=B){const[n,t]=k(P(e,window.innerWidth));return w(()=>{let r=[],l=[];const o=()=>{l.forEach(c=>c()),r=[],l=[];const i=P(e,window.innerWidth);t(i);const m=S.indexOf(i),d=S[m+1];if(d&&e[d]!==void 0){const c=e[d];if(Number.isNaN(c))throw new Error(`Invalid breakpoint value for ${d}: ${e[d]}`);{const u=window.matchMedia(`(min-width: ${c}px)`);r.push(u);const f=()=>o();u.addEventListener("change",f),l.push(()=>u.removeEventListener("change",f))}}const s=S[m-1];if(s&&e[s]!==void 0){const c=e[s];if(Number.isNaN(c))throw new Error(`Invalid breakpoint value for ${s}: ${e[s]}`);{const u=window.matchMedia(`(max-width: ${c-1}px)`);r.push(u);const f=()=>o();u.addEventListener("change",f),l.push(()=>u.removeEventListener("change",f))}}};return o(),()=>{l.forEach(i=>i())}},[e]),n}const R=G("base");function ye({children:e,breakpointDesc:n}){const t=W(n);return a.createElement(R.Provider,{value:t},e)}function Se(){return q(R)}export{se as ArrayRender,ye as BreakpointProvider,pe as Counter,ie as DateRender,B as DefBreakpointDesc,X as False,p as If,ae as Observer,te as Pipe,re as Scope,ne as SizeBox,O as Styles,y as Switch,le as Toggle,Q as True,ee as When,S as breakpoints,Y as childrenLoop,J as createExternalState,me as createStorageState,F as cx,he as formatDate,P as getCurrentBreakpoint,j as safePromiseTry,Se as useBreakpoint,de as useControlled,W as useScreen};
1
+ import s,{useMemo as g,Fragment as S,Children as L,isValidElement as H,cloneElement as V,useEffect as w,useState as O,useRef as k,useCallback as Z}from"react";function Y(e,n){if(e===void 0)return;let t=0;if(Array.isArray(e)){for(const r of e)if(n(r,t++)===!1)break}else n(e,t)}const z=(e,n)=>e===n,v=e=>s.createElement(s.Fragment,null,e.children);v.displayName="Switch_Case";const N=e=>s.createElement(s.Fragment,null,e.children);N.displayName="Switch_Default";const y=e=>{const{value:n,compare:t=z,children:r,strict:l=!1}=e,o=new Set;let a=null,u=null,d=!1;return Y(r,(i,c)=>{if(!s.isValidElement(i))throw new Error(`Switch Children only accepts valid React elements at index ${c}`);const f=i.type;if(f.displayName===v.displayName){const m=i.props;if(o.has(m.value))throw new Error(`Switch found duplicate Case value at index ${c}: ${JSON.stringify(m.value)}${l?" (detected in strict mode)":""}`);if(o.add(m.value),!a&&t(n,m.value)&&(a=m.children,l===!1))return!1}else if(f.displayName===N.displayName){if(d)throw new Error(`Switch can only have one Default child at index ${c}`);if(d=!0,u=i.props.children,!l&&a)return!1}else throw new Error(`Switch Children only accepts 'Case' or 'Default' elements, found: ${String(f.displayName||f.name||f)} at index ${c}`)}),s.createElement(s.Fragment,null,a??u)};y.displayName="Switch",y.Case=v,y.Default=N,y.createTyped=function(){return{Switch:y,Case:v,Default:N}};const b=e=>s.createElement(s.Fragment,null,e.children),M=({children:e})=>s.createElement(s.Fragment,null,e),x=e=>s.createElement(s.Fragment,null,e.children);b.displayName="If_Then",M.displayName="If_Else",x.displayName="If_ElseIf";const p=({condition:e,children:n})=>{let t=null,r=null;const l=[];if(s.Children.forEach(n,o=>{if(!s.isValidElement(o))throw new Error("If component only accepts valid React elements");const a=o.type;if(a.displayName===b.displayName){if(t)throw new Error("If component can only have one Then child");t=o}else if(a.displayName===x.displayName)l.push(o);else if(a.displayName===M.displayName){if(r)throw new Error("If component can only have one Else child");r=o}else throw new Error(`If component only accepts 'Then', 'ElseIf', or 'Else' elements as children, found: ${String(a.displayName||a.name||a)}`)}),e)return t?s.createElement(s.Fragment,null,t.props.children):null;for(const o of l)if(o.props.condition)return s.createElement(s.Fragment,null,o.props.children);return r?s.createElement(s.Fragment,null,r.props.children):null};p.displayName="If",p.Then=b,p.ElseIf=x,p.Else=M,p.createTyped=function(){return{If:p,Then:b,ElseIf:x,Else:M}};const U=({condition:e,children:n})=>e?s.createElement(s.Fragment,null,n):null,G=({condition:e,children:n})=>e===!1?s.createElement(s.Fragment,null,n):null,q=({all:e,any:n,none:t,children:r,fallback:l})=>g(()=>(e&&(n||t)&&console.warn('When: Multiple condition types (all, any, none) provided; "all" takes precedence.'),!!(e&&e.length>0&&e.every(Boolean)||n&&n.length>0&&n.some(Boolean)||t&&t.length>0&&t.every(o=>!o))),[e,n,t])?s.createElement(s.Fragment,null,r):s.createElement(s.Fragment,null,l||null),K=({data:e,transform:n,render:t,fallback:r})=>{const l=g(()=>n.reduce((o,a)=>a(o),e),[e,n]);return l==null?s.createElement(s.Fragment,null,r||null):s.createElement(s.Fragment,null,t(l))},Q=e=>{const{children:n,h:t,w:r,size:l,height:o,width:a,className:u}=e;return s.createElement("div",{style:{width:l||r||a,height:l||t||o,flexShrink:0},className:u},n)},X=({let:e,props:n,children:t,fallback:r})=>{const l=g(()=>typeof e=="function"?e(n):e,[e,n]);return!t||!Object.keys(l).length?s.createElement(s.Fragment,null,r||null):s.createElement(s.Fragment,null,t(l))};function F(...e){const n=new Set;for(const t of e)if(t){if(typeof t=="string")n.add(t);else if(Array.isArray(t))t.forEach(r=>n.add(r));else if(typeof t=="object")for(const[r,l]of Object.entries(t))l&&n.add(r)}return Array.from(n).join(" ")}const ee=e=>typeof e=="object"&&!!e,C=({className:e,children:n,asWrapper:t=!1})=>{if(!n)return null;if(!e)return s.createElement(S,null,n);const r=typeof e=="string"?e:F(...Object.values(e));if(t)return s.createElement(t===!0?"div":t,{className:r},n);if(L.count(n)>1)return console.error("<Styles>: children has more than one child. Please check your code."),s.createElement(S,null,n);if(H(n)){const l=n;let o=l?.props?.className;return l?.type?.displayName===C.displayName&&ee(o)&&(o=F(...Object.values(o))),V(n,{className:F(r,o)})}return console.error("<Styles>: children is not a valid React element. Please check your code."),s.createElement(S,null,n)};C.displayName="W/Styles";const te=e=>{const{index:n=0,options:t,next:r,render:l}=e;w(()=>{if(t.length<n+1)throw new Error(`Index ${n} is out of bounds for options array of length ${t.length}. Defaulting to first option.`)},[n,t]);const[o,a]=O(n),u=()=>{a(d=>t.length?r?r(d,t):(d+1)%t.length:d)};return l(t[o],u)},ne=({onIntersect:e,threshold:n=.1,root:t=null,rootMargin:r="0px",triggerOnce:l=!1,disabled:o=!1,children:a,className:u,style:d})=>{const i=k(null),c=k(null),f=k(!1);return w(()=>{if(o||!i.current)return;if(!window.IntersectionObserver){console.warn("IntersectionObserver is not supported in this browser");return}const m=i.current,h=I=>{I.forEach(D=>{l&&f.current||(e(D,c.current),l&&(f.current=!0,c.current?.unobserve(m)))})};return c.current=new IntersectionObserver(h,{root:t,rootMargin:r,threshold:n}),c.current.observe(m),()=>{c.current&&c.current.disconnect()}},[e,n,t,r,l,o]),w(()=>{l||(f.current=!1)},[l]),s.createElement("div",{ref:i,className:u,style:d},a)};function re(e){const{items:n,renderItem:t,filter:r,renderEmpty:l,sort:o}=e;if(!n)return console.error("ArrayRender: items is null"),null;if(n.length===0)return l?l():null;if(o){let a=[...n];return r&&(a=a.filter(r)),a=a.sort(o),a.length===0?l?l():null:s.createElement(S,null,a.map((u,d)=>t(u,d)))}return s.createElement(S,null,n.map((a,u)=>r&&!r(a)?null:t(a,u)))}function le({source:e,format:n,children:t}){const r=g(()=>{if(e instanceof Date)return e;if(typeof e=="string"||typeof e=="number"){const o=new Date(e);return isNaN(o.getTime())?null:o}return null},[e]),l=g(()=>r?n?n(r):r.toLocaleString():null,[r,n]);return!l||!t?null:s.createElement(s.Fragment,null,t(l))}const oe="onChange",ae="value";function se(e){const{defaultValue:n,onBeforeChange:t,trigger:r=oe,valuePropName:l=ae,props:o}=e,a=Object.prototype.hasOwnProperty.call(o,l),[u,d]=O(n),i=a?o[l]:u,c=g(()=>o[r],[o,r]),f=Z(m=>{const h=typeof m=="function"?m(i):m;t&&t(h,i)===!1||(a||d(h),c&&c(h))},[a,t,i,c]);return[i,f]}function ie(e,...n){try{const t=e(...n);return t instanceof Promise?t:Promise.resolve(t)}catch(t){return Promise.reject(t)}}const j=typeof Promise.try=="function"?Promise.try.bind(Promise):ie;function J(e,n={}){let t=typeof e=="function"?e():e;const r=[],{sideEffect:l,transform:o}=n,a=()=>{const i=t;return o?.get?o.get(i):i},u=i=>{const c=t,f=o?.get?o.get(c):c;t=o?.set?o.set(typeof i=="function"?i(f):i):typeof i=="function"?i(f):i,r.forEach(m=>m(t)),l&&j(l,t,c).catch(m=>{console.error("Error in external state side effect, Please do it within side effects:",m)})},d=()=>{const[i,c]=s.useState(t);return s.useEffect(()=>(r.push(c),()=>{const f=r.indexOf(c);f>-1&&r.splice(f,1)}),[]),[o?.get?o.get(i):i,u]};return{get:a,set:u,use:d,useGetter:()=>{const[i]=d();return i},__listeners:r}}function ce(e,n,t){const{storageType:r="local",sideEffect:l,transform:o}=t??{},a=r==="local"?localStorage:sessionStorage;let u=n;const d=a.getItem(e);if(d)try{u=JSON.parse(d)}catch(i){console.warn(`Failed to parse ${r}Storage value for key "${e}", using initial state:`,i),u=n}return J(u,{sideEffect:i=>{a.setItem(e,JSON.stringify(i)),l?.(i)},transform:o})}function ue(e,n){const t=n||new Date,r=t.getFullYear(),l=t.getMonth()+1,o=t.getDate(),a=t.getHours(),u=t.getMinutes(),d=t.getSeconds(),i=t.getMilliseconds(),c=t.getDay(),f=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],m=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],I=["January","February","March","April","May","June","July","August","September","October","November","December"],D=m[c],A=f[c],P=l-1,B=I[P],R=h[P],_={YY:r.toString().slice(2),YYYY:r.toString(),M:l.toString(),MM:l.toString().padStart(2,"0"),MMM:R,MMMM:B,D:o.toString(),DD:o.toString().padStart(2,"0"),d:c.toString(),dd:A,ddd:A,dddd:D,H:a.toString(),HH:a.toString().padStart(2,"0"),h:(a%12).toString(),hh:(a%12).toString().padStart(2,"0"),m:u.toString(),mm:u.toString().padStart(2,"0"),s:d.toString(),ss:d.toString().padStart(2,"0"),SSS:i.toString().padStart(3,"0"),Z:"+08:00",ZZ:"+0800",A:a<12?"AM":"PM",a:a<12?"am":"pm"};return e.replace(/YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|Z{1,2}|A|a/g,$=>_[$])}class de{count=0;next(){return this.count++}}const E=["base","xs","sm","md","lg","xl","2xl","3xl"],W={xs:475,sm:640,md:768,lg:1024,xl:1280,"2xl":1536,"3xl":1920},fe=[...E].reverse();function T(e,n){for(const t of fe){const r=e[t];if(r!==void 0&&!Number.isNaN(r)&&n>=r)return t}return"base"}function me(e=W){const[n,t]=O(T(e,window.innerWidth));return w(()=>{let r=[],l=[];const o=()=>{l.forEach(c=>c()),r=[],l=[];const a=T(e,window.innerWidth);t(a);const u=E.indexOf(a),d=E[u+1];if(d&&e[d]!==void 0){const c=e[d];if(Number.isNaN(c))throw new Error(`Invalid breakpoint value for ${d}: ${e[d]}`);{const f=window.matchMedia(`(min-width: ${c}px)`);r.push(f);const m=()=>o();f.addEventListener("change",m),l.push(()=>f.removeEventListener("change",m))}}const i=E[u-1];if(i&&e[i]!==void 0){const c=e[i];if(Number.isNaN(c))throw new Error(`Invalid breakpoint value for ${i}: ${e[i]}`);{const f=window.matchMedia(`(max-width: ${c-1}px)`);r.push(f);const m=()=>o();f.addEventListener("change",m),l.push(()=>f.removeEventListener("change",m))}}};return o(),()=>{l.forEach(a=>a())}},[e]),n}export{re as ArrayRender,de as Counter,le as DateRender,W as DefBreakpointDesc,G as False,p as If,ne as Observer,K as Pipe,X as Scope,Q as SizeBox,C as Styles,y as Switch,te as Toggle,U as True,q as When,E as breakpoints,Y as childrenLoop,J as createExternalState,ce as createStorageState,F as cx,ue as formatDate,T as getCurrentBreakpoint,j as safePromiseTry,se as useControlled,me as useScreen};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wwog/react",
3
- "version": "1.3.5",
3
+ "version": "1.3.8",
4
4
  "description": "A practical React component library providing declarative flow control and common UI utility components to make your React code more concise and readable.",
5
5
  "keywords": [
6
6
  "react",
@@ -0,0 +1,80 @@
1
+ /*
2
+ 蔡勒公式(德语:Zellers Kongruenz),是一种计算任何一日属一星期中哪一日的算法,由十九世纪德国数学家克里斯提安·蔡勒推算出来。
3
+
4
+ 对于公历,蔡勒公式为
5
+ h = (q + [13(m + 1)/5] + K + [K/4] + [J/4] - 2J) mod 7
6
+ 对于儒略历,蔡勒公式为
7
+ h = (q + [13(m + 1)/5] + K + [K/4] + 5 - J) mod 7
8
+
9
+ h 表示星期几(0 = 星期六,1 = 星期日,2 = 星期一,...,6 = 星期五)
10
+ q 代表月份中的日期
11
+ m 代表月份(3=三月,4=四月,5=五月,...,14=二月)
12
+ K 代表世纪中的年份 ((adjYear) mod 100)
13
+ J 是从零开始的世纪数(实际上是 ⌊(adjYear)/100⌋)
14
+ [...] 表示取整函数
15
+ 注意:在此算法中,一月和二月被视为上一年的第 13 和第 14 个月。
16
+ 对于ISO 周期中的星期几 d (1 ..= 7)
17
+ d = ((h + 5) mod 7) + 1
18
+
19
+ 上面公式依赖于数学家对模除法的定义,即−2 mod 7 等于正 5。
20
+ 遗憾的是,在大多数计算机语言实现取余函数时采用截断方式,−2 mod 7 会返回−2 的结果。
21
+ 因此,要在计算机上实现泽勒同余,应略微调整公式以确保分子为正。
22
+ 最简单的办法是将−2J 替换为+5J,将−J 替换为+6J。
23
+
24
+ 对于公历,蔡勒公式变体为:
25
+ h = (q + [13(m + 1)/5] + K + [K / 4] + [J / 4] + 5J) mod 7
26
+ 对于儒略历,蔡勒公式变体为:
27
+ h = (q + [13(m + 1)/5] + K + [K / 4] + 5 + 6J) mod 7
28
+
29
+ 在使用计算机时,年份处理为4位数更简单,因此RFC 3339附录B中提及用于公历的情况
30
+ 对于公历, 变体为:
31
+ h + (q + [ 13(m +1) /5] + Y + [Y /4] -[Y/100] + [Y/400] ) mod 7
32
+ 对于儒略历, 变体为:
33
+ h = (q + [13(m + 1)/5] + Y + [Y / 4] + 5) mod 7
34
+
35
+ */
36
+
37
+ /**
38
+ * 计算给定日期的星期几(基于 Michael Keith & Tom Craver 的优化算法)仅公历
39
+ * @param y - 年份(4位数,如 2023)
40
+ * @param m - 月份(1-12)
41
+ * @param d - 日期(1-31)
42
+ * @returns 星期几(0=周日, 1=周一, ..., 6=周六)
43
+ */
44
+ export function weekday(y: number, m: number, d: number): number {
45
+ const adjustedY = m < 3 ? y - 1 : y - 2;
46
+ const adjustedD = d + adjustedY;
47
+ return (
48
+ (Math.floor((23 * m) / 9) +
49
+ adjustedD +
50
+ 4 +
51
+ Math.floor(y / 4) -
52
+ Math.floor(y / 100) +
53
+ Math.floor(y / 400)) %
54
+ 7
55
+ );
56
+ }
57
+
58
+ /**
59
+ * 计算儒略历日期的星期几
60
+ * @param y - 年份(4位数,如 1582)
61
+ * @param m - 月份(1-12)
62
+ * @param d - 日期(1-31)
63
+ * @returns 星期几(0=周六, 1=周日, ..., 6=周五)
64
+ */
65
+ export function weekdayJulian(y: number, m: number, d: number): number {
66
+ const adjustedY = m < 3 ? y - 1 : y;
67
+ const adjustedD = d + adjustedY;
68
+ if (m < 3) {
69
+ m += 12;
70
+ y--;
71
+ }
72
+ return (
73
+ (adjustedD +
74
+ Math.floor((13 * (m + 1)) / 5) +
75
+ adjustedY +
76
+ Math.floor(adjustedY / 4) +
77
+ 5) %
78
+ 7
79
+ );
80
+ }
@@ -0,0 +1,5 @@
1
+ import * as zllersKongruenz from "./date/zellersKongruenz";
2
+
3
+ export const weekday = {
4
+ zllersKongruenz,
5
+ };
@@ -5,18 +5,48 @@ export interface ArrayRenderProps<T> {
5
5
  items: T[];
6
6
  renderItem: (item: T, index: number) => React.ReactNode;
7
7
  filter?: (item: T) => boolean;
8
+ renderEmpty?: () => React.ReactNode;
9
+ sort?: (a: T, b: T) => number;
8
10
  }
9
11
  //#endregion component Types
10
12
 
11
13
  //#region component
12
14
  export function ArrayRender<T>(props: ArrayRenderProps<T>): ReactNode {
13
- const { items, renderItem, filter } = props;
15
+ const { items, renderItem, filter, renderEmpty, sort } = props;
14
16
 
15
17
  if (!items) {
16
18
  console.error("ArrayRender: items is null");
17
19
  return null;
18
20
  }
19
21
 
22
+ if (items.length === 0) {
23
+ return renderEmpty ? renderEmpty() : null;
24
+ }
25
+
26
+ // 如果需要排序,先处理排序和过滤
27
+ if (sort) {
28
+ let processedItems = [...items];
29
+
30
+ if (filter) {
31
+ processedItems = processedItems.filter(filter);
32
+ }
33
+
34
+ processedItems = processedItems.sort(sort);
35
+
36
+ if (processedItems.length === 0) {
37
+ return renderEmpty ? renderEmpty() : null;
38
+ }
39
+
40
+ return (
41
+ <Fragment>
42
+ {processedItems.map((item, index) => {
43
+ return renderItem(item, index);
44
+ })}
45
+ </Fragment>
46
+ );
47
+ }
48
+
49
+ // 如果不需要排序,保持原来的循环中过滤方式
20
50
  return (
21
51
  <Fragment>
22
52
  {items.map((item, index) => {
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useEffect, useState } from "react";
1
+ import { useEffect, useState } from "react";
2
2
  import {
3
3
  breakpoints,
4
4
  DefBreakpointDesc,
@@ -97,24 +97,3 @@ export function useScreen(breakpointDesc: BreakpointDesc = DefBreakpointDesc) {
97
97
 
98
98
  return currentBreakpoint;
99
99
  }
100
-
101
- const BreakpointContext = createContext<BreakpointName>("base");
102
-
103
- export function BreakpointProvider({
104
- children,
105
- breakpointDesc,
106
- }: {
107
- children: React.ReactNode;
108
- breakpointDesc?: BreakpointDesc;
109
- }) {
110
- const breakpoint = useScreen(breakpointDesc);
111
- return (
112
- <BreakpointContext.Provider value={breakpoint}>
113
- {children}
114
- </BreakpointContext.Provider>
115
- );
116
- }
117
-
118
- export function useBreakpoint() {
119
- return useContext(BreakpointContext);
120
- }