@contractspec/lib.design-system 4.0.0 → 4.2.0
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 +24 -2
- package/dist/browser/components/atoms/Input.js +1 -1
- package/dist/browser/components/data-view/DataViewRenderer.js +1 -1
- package/dist/browser/components/forms/controls/Autocomplete.js +1 -1
- package/dist/browser/components/forms/controls/Select.js +1 -1
- package/dist/browser/components/forms/controls/select-options.js +1 -0
- package/dist/browser/components/molecules/FiltersToolbar.js +1 -1
- package/dist/browser/hooks/useListUrlState.js +1 -1
- package/dist/browser/theme/tailwind-css.js +5 -5
- package/dist/components/atoms/Input.js +1 -1
- package/dist/components/data-view/DataViewRenderer.d.ts +3 -3
- package/dist/components/data-view/DataViewRenderer.js +1 -1
- package/dist/components/data-view/DataViewRenderer.native.d.ts +3 -3
- package/dist/components/forms/controls/Autocomplete.d.ts +9 -1
- package/dist/components/forms/controls/Autocomplete.js +1 -1
- package/dist/components/forms/controls/Autocomplete.native.d.ts +5 -1
- package/dist/components/forms/controls/Select.d.ts +7 -5
- package/dist/components/forms/controls/Select.js +1 -1
- package/dist/components/forms/controls/Select.native.d.ts +7 -5
- package/dist/components/forms/controls/index.d.ts +1 -1
- package/dist/components/forms/controls/select-options.d.ts +17 -0
- package/dist/components/forms/controls/select-options.js +1 -0
- package/dist/components/molecules/FiltersToolbar.d.ts +1 -0
- package/dist/components/molecules/FiltersToolbar.js +1 -1
- package/dist/hooks/useListUrlState.d.ts +3 -1
- package/dist/hooks/useListUrlState.js +1 -1
- package/dist/native/components/atoms/Input.js +1 -1
- package/dist/native/components/atoms/Input.native.js +1 -1
- package/dist/native/components/data-view/DataViewRenderer.js +1 -1
- package/dist/native/components/data-view/DataViewRenderer.native.js +1 -1
- package/dist/native/components/forms/controls/Autocomplete.js +1 -1
- package/dist/native/components/forms/controls/Autocomplete.native.js +1 -1
- package/dist/native/components/forms/controls/Select.js +1 -1
- package/dist/native/components/forms/controls/Select.native.js +1 -1
- package/dist/native/components/forms/controls/select-options.js +1 -0
- package/dist/native/components/molecules/FiltersToolbar.js +1 -1
- package/dist/native/components/molecules/FiltersToolbar.native.js +1 -1
- package/dist/native/hooks/useListUrlState.js +1 -1
- package/dist/native/theme/tailwind-css.js +5 -5
- package/dist/theme/tailwind-css.js +5 -5
- package/package.json +19 -7
package/README.md
CHANGED
|
@@ -154,9 +154,25 @@ import {
|
|
|
154
154
|
componentKey="Select"
|
|
155
155
|
options={[{ labelI18n: "status.draft", value: "draft" }]}
|
|
156
156
|
/>
|
|
157
|
+
<Select
|
|
158
|
+
componentKey="Select"
|
|
159
|
+
groups={[
|
|
160
|
+
{
|
|
161
|
+
labelI18n: "status.lifecycle",
|
|
162
|
+
options: [{ labelI18n: "status.draft", value: "draft" }],
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
labelI18n: "status.release",
|
|
166
|
+
options: [{ labelI18n: "status.published", value: "published" }],
|
|
167
|
+
},
|
|
168
|
+
]}
|
|
169
|
+
/>
|
|
157
170
|
</DesignSystemThemeProvider>;
|
|
158
171
|
```
|
|
159
172
|
|
|
173
|
+
When both `options` and `groups` are provided to `Select`, grouped options are
|
|
174
|
+
used and the flat `options` list is ignored.
|
|
175
|
+
|
|
160
176
|
### Use form controls from the design-system boundary
|
|
161
177
|
|
|
162
178
|
The root barrel exposes themed and translation-aware controls for product
|
|
@@ -170,6 +186,11 @@ surfaces: `Button`, `Input`, `Textarea`, `Select`, `NativeSelect`,
|
|
|
170
186
|
`FieldSeparator` wrappers so contract-driven forms can preserve accessible
|
|
171
187
|
legend, description, invalid, and grouped-control structure.
|
|
172
188
|
|
|
189
|
+
The `Autocomplete` control renders through the shared combobox primitive on web
|
|
190
|
+
and keeps native rendering aligned for query, selected options, loading, error,
|
|
191
|
+
and empty states. FormSpec renderers pass resolver-backed async state through
|
|
192
|
+
these props without requiring product surfaces to know the underlying transport.
|
|
193
|
+
|
|
173
194
|
### Render forms on mobile through the shared renderer
|
|
174
195
|
|
|
175
196
|
Use the focused shared renderer subpath when rendering `FormSpec` contracts in
|
|
@@ -285,10 +306,11 @@ hidden-column recovery without widening the primitive table API.
|
|
|
285
306
|
### Renderers and hooks
|
|
286
307
|
|
|
287
308
|
- renderer exports from `./renderers`
|
|
288
|
-
- form-contract renderer support, including readonly, password, autocomplete, address, phone, date, time, datetime, semantic FormSpec groups, grid layout hints, and text/textarea input groups
|
|
309
|
+
- form-contract renderer support, including readonly, email, password, autocomplete, address, phone, date, time, datetime, semantic FormSpec groups, grid layout hints, progressive FormSpec sections/steps, mobile-safe FormSpec column helper output, and text/textarea/email input groups
|
|
289
310
|
- translation-aware rendering through `DesignSystemTranslationProvider` and `createTranslationResolver`
|
|
290
311
|
- theme-aware form controls and stack primitives that consume ThemeSpec component variant props
|
|
291
|
-
- hooks such as `useListUrlState
|
|
312
|
+
- hooks such as `useListUrlState`, including scoped list filters where locked constraints are excluded from user-editable URL state
|
|
313
|
+
- DataViewRenderer filter chips for scoped DataView filters, including disabled locked chips on web and native surfaces
|
|
292
314
|
- navigation-related shared types
|
|
293
315
|
|
|
294
316
|
### Component composition layers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:
|
|
1
|
+
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:D,defaultValue:E,onChange:G,onSubmit:O,onFocus:H,onBlur:J,placeholder:M,disabled:P,readOnly:Q,maxLength:R,name:S,className:U,keyboard:z,componentKey:X,themeVariant:Y,placeholderI18n:Z,ariaLabelI18n:$,...A}){const _=z?B(z):{},q=C({defaultComponentKey:"Input",componentKey:X,themeVariant:Y,className:U,style:A.style,placeholder:M,placeholderI18n:Z,ariaLabelI18n:$});return N(j,{...q.themed.props,..._,...A,className:q.themed.className,style:q.themed.style,value:D,defaultValue:E,onChange:G,onFocus:H,onBlur:J,placeholder:q.placeholder,"aria-label":q.ariaLabel,disabled:P,readOnly:Q,maxLength:R,name:S})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as J,jsxs as c,Fragment as p}from"react/jsx-runtime";import{resolveDataViewFilters as S}from"@contractspec/lib.contracts-spec/data-views";import{Pagination as d}from"@contractspec/lib.ui-kit-web/ui/atoms/Pagination";import{VStack as h}from"@contractspec/lib.ui-kit-web/ui/stack";import{Text as f}from"@contractspec/lib.ui-kit-web/ui/text";import*as L from"react";import{resolveTranslationString as V,useDesignSystemTranslation as u}from"../../i18n/translation";import{FiltersToolbar as m}from"../molecules/FiltersToolbar";import{DataViewDetail as v}from"./DataViewDetail";import{DataViewList as b}from"./DataViewList";import{DataViewTable as y}from"./DataViewTable";export function DataViewRenderer({spec:B,items:G=[],item:X=null,className:M,renderActions:$,onSelect:q,onRowClick:P,toolbar:R,loading:T,headerActions:Y,emptyState:Q,footer:j,search:w,onSearchChange:_,filters:I,onFilterChange:Z,pagination:K,onPageChange:D}){const z=u(),O=L.useMemo(()=>S({filters:B.view.filters,scope:B.view.filterScope,user:g(I)}),[I,B.view.filterScope,B.view.filters]),N=L.useMemo(()=>{if(B.view.filterScope){const E=Object.entries(O.user).map(([H,W])=>({key:H,label:`${A(B,H)}: ${F(W)}`,onRemove:()=>{const{[H]:r,...C}=O.user;Z?.(C)}})),U=O.lockedChips==="hidden"?[]:Object.entries(O.locked).map(([H,W])=>({key:`locked-${H}`,label:`${A(B,H)}: ${F(W)}`,disabled:!0}));return[...E,...U]}return I?Object.entries(I).map(([E,U])=>({key:E,label:`${E}: ${String(U)}`,onRemove:()=>{const{[E]:H,...W}=I;Z?.(W)}})):[]},[I,Z,O,B]),k=B.view.filterScope?Object.keys(O.user).length>0:Boolean(I&&Object.keys(I).length>0),x=L.useMemo(()=>{switch(B.view.kind){case"list":return J(b,{spec:B,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q});case"table":return J(y,{spec:B,items:G,className:M,onRowClick:P,toolbar:R,loading:T,emptyState:Q,headerActions:Y,footer:j});case"detail":return J(v,{spec:B,item:X,className:M,emptyState:Q,headerActions:Y});case"grid":{const E=B.view,U={kind:"list",layout:"card",fields:E.fields,filters:E.filters,actions:E.actions,primaryField:E.primaryField,secondaryFields:E.secondaryFields,filterScope:E.filterScope},H={...B,view:U};return J(b,{spec:H,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q})}default:return J(f,{className:M,children:V("Unsupported data view kind",z)})}},[B,G,X,M,$,q,P,R,T,Y,Q,j,z]);if(!(B.view.kind==="list"||B.view.kind==="table"||B.view.kind==="grid"))return J(p,{children:x});return c(h,{gap:"lg",children:[(B.view.filters?.length||_||N.length)&&J(m,{searchValue:w,onSearchChange:_,searchPlaceholder:V("Search...",z)??"Search...",activeChips:N,onClearAll:k?()=>Z?.({}):void 0,right:B.view.kind==="table"?void 0:Y}),x,K&&K.total>0&&J(d,{currentPage:K.page,totalPages:Math.ceil(K.total/K.pageSize),totalItems:K.total,itemsPerPage:K.pageSize,onPageChange:(E)=>D?.(E),onItemsPerPageChange:(E)=>{D?.(1)},showItemsPerPage:!1})]})}function g(B){if(!B)return;return Object.fromEntries(Object.entries(B??{}).filter((G)=>Boolean(G[1]&&typeof G[1]==="object"&&"kind"in G[1]&&typeof G[1].kind==="string")))}function A(B,G){return B.view.filters?.find((X)=>X.key===G)?.label??G}function F(B){if(!B)return"";if(B.kind==="single")return String(B.value);if(B.kind==="multi")return B.values.map(String).join(", ");if(B.kind==="range")return[B.from==null?"":String(B.from),B.to==null?"":String(B.to)].filter(Boolean).join(" - ");return`${B.mode}(${B.clauses.length})`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as v}from"react/jsx-runtime";import{Combobox as I}from"@contractspec/lib.ui-kit-web/ui/combobox";import{useThemedPrimitive as T,useTranslatedText as b}from"../../primitives/themed";function H(E){return typeof E==="string"?E:String(E??"")}function g(E,U){const F=new Set,J=[];for(const L of[...U,...E]){const M=H(L.value);if(F.has(M))continue;F.add(M);J.push(L)}return J}export function Autocomplete({query:E,options:U,selectedOptions:F,onQueryChange:J,onSelectOption:L,onRemoveOption:M,multiple:W,placeholder:X,placeholderI18n:Y,readOnly:_,disabled:j,className:q,componentKey:w,themeVariant:D,emptyText:K="No results found.",loadingText:N="Loading options...",errorText:Q="Unable to load options.",loading:R,error:Z,id:S,name:k,"aria-invalid":C,"aria-describedby":B}){const A=b(),$=T({defaultComponentKey:"Autocomplete",componentKey:w,themeVariant:D,className:q}),f=g(U,F),P=new Map(f.map((z)=>[H(z.value),z]));return v(I,{...$.props,id:S,name:k,className:$.className,options:f.map((z)=>({value:H(z.value),label:A(z.labelI18n)??z.labelI18n,description:z.descriptionI18n?A(z.descriptionI18n)??z.descriptionI18n:void 0,disabled:z.disabled})),value:W?void 0:H(F[0]?.value??""),selectedValues:W?F.map((z)=>H(z.value)):void 0,query:E,onQueryChange:J,onValueChange:(z)=>{const G=P.get(z);if(G)L?.(G)},onRemoveValue:(z)=>{const G=P.get(z);if(G)M?.(G)},multiple:W,placeholder:A(Y??X),searchPlaceholder:A(Y??X),emptyText:A(K),loadingText:A(N),errorText:A(Q),loading:R,error:Z?A(Z):null,readOnly:_,disabled:j,"aria-invalid":C,"aria-describedby":B})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as z,jsxs as M}from"react/jsx-runtime";import{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue,Select as K}from"@contractspec/lib.ui-kit-web/ui/select";import{useThemedPrimitive as O,useTranslatedText as T}from"../../primitives/themed";import{selectGroupKey as v,selectGroupLabel as w,selectOptionGroups as G,selectOptionLabel as L,selectOptionValue as D}from"./select-options";export function Select({options:Q,groups:R,value:E,onChange:U,placeholder:X,disabled:Y,className:Z,componentKey:$,themeVariant:k,placeholderI18n:P,...W}){const B=T(),N=O({defaultComponentKey:"Select",componentKey:$,themeVariant:k,className:Z}),C=G({options:Q,groups:R});return M(K,{value:E==null?"":D(E),onValueChange:(q)=>U?.(q),disabled:Y,...W,children:[z(SelectTrigger,{className:N.className,children:z(SelectValue,{placeholder:B(P??X)})}),z(SelectContent,{children:C.map((q,F)=>{const H=v(q,F),J=w(q,B);return M(SelectGroup,{children:[J?z(SelectLabel,{children:J}):null,q.options.map((A,f)=>z(SelectItem,{value:D(A.value),disabled:A.disabled,children:L(A,B)},`${H}-${D(A.value)}-${f}`))]},`${H}-${F}`)})})]})}export{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function selectOptionValue(e){return typeof e==="string"?e:String(e??"")}export function selectOptionLabel(e,t){return t(e.labelI18n)??selectOptionValue(e.labelI18n)}export function selectGroupLabel(e,t){return t(e.labelI18n??e.label)}export function selectGroupKey(e,t){return e.key??e.labelI18n??e.label??`group-${t}`}export function selectOptionGroups({options:e,groups:t}){return t?.length?t:[{options:e??[]}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as
|
|
1
|
+
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as I}from"@contractspec/lib.ui-kit-web/ui/badge";import{cn as W}from"@contractspec/lib.ui-kit-web/ui/utils";import*as K from"react";import{Button as X}from"../atoms/Button";import{Input as N}from"../atoms/Input";export function FiltersToolbar({className:Y,children:Z,right:$,searchPlaceholder:k,searchValue:G,onSearchChange:F,onSearchSubmit:L,debounceMs:O=250,activeChips:T=[],onClearAll:H}){const[J,U]=K.useState(G??"");K.useEffect(()=>{U(G??"")},[G]);K.useEffect(()=>{if(!F)return;const z=setTimeout(()=>F(J),O);return()=>clearTimeout(z)},[J,O,F]);return D("div",{className:W("space-y-2",Y),children:[D("div",{className:"flex flex-col items-stretch gap-2 md:flex-row md:items-center md:justify-between",children:[D("div",{className:"flex flex-1 items-center gap-2",children:[F?D("div",{className:"flex flex-1 items-center gap-2",children:[E(N,{value:J,onChange:(z)=>U(z.target.value),onKeyDown:(z)=>{if(z.key==="Enter")L?.()},placeholder:k,keyboard:{kind:"search"}}),E(X,{variant:"outline",onPress:()=>L?.(),className:"shrink-0",children:"Rechercher"})]}):null,Z]}),$]}),(T.length>0||H)&&D("div",{className:"flex flex-wrap items-center gap-2",children:[T.map((z)=>D(I,{variant:"secondary",className:W("inline-flex items-center gap-2",z.disabled&&"opacity-70"),children:[E("span",{children:z.label}),z.onRemove&&!z.disabled&&E("button",{type:"button","aria-label":"Supprimer le filtre",onClick:z.onRemove,className:"rounded-xs px-1 text-base hover:bg-muted",children:"×"})]},z.key)),H&&E(X,{size:"sm",variant:"ghost",onPress:H,children:"Effacer les filtres"})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import{createInitialListFilters as N,sanitizeListUserFilters as _}from"@contractspec/lib.presentation-runtime-core";import*as Q from"react";export function useListUrlState({defaults:E,paramKeys:h={q:"q",page:"page",limit:"limit",sort:"sort",filters:"f"},replaceState:$=!0,filterScope:J}){const Y=Q.useMemo(()=>({...N(J),..._(E.filters,J)}),[E.filters,J]),Z=Q.useCallback(()=>{if(typeof window>"u")return E;const A=new URL(window.location.href).searchParams,V=(X,M)=>{const H=X?Number(X):NaN;return Number.isFinite(H)&&H>0?H:M},C=A.get(h.filters);let B=E.filters;if(C)try{B=_(JSON.parse(C),J)}catch{B=Y}else B=Y;return{q:A.get(h.q)??E.q,page:V(A.get(h.page),E.page),limit:V(A.get(h.limit),E.limit),sort:A.get(h.sort),filters:B}},[Y,E,J,h]),[T,b]=Q.useState(Z),W=Q.useCallback((G)=>{if(typeof window>"u")return;const A=new URL(window.location.href),V=A.searchParams,C={...T,...G,filters:_(G.filters??T.filters,J)},B=(M,H)=>{if(H==null||H===""||H==="null")V.delete(M);else V.set(M,H)};B(h.q,C.q||null);B(h.page,String(C.page));B(h.limit,String(C.limit));B(h.sort,C.sort??null);try{const M=JSON.stringify(C.filters??{});B(h.filters,M==="{}"?null:M)}catch{}const X=`${A.pathname}?${V.toString()}${A.hash}`;if($)window.history.replaceState({},"",X);else window.history.pushState({},"",X);b(C)},[J,T,h,$]),I=Q.useCallback((G,A)=>{W({filters:{...T.filters,[G]:A}})},[T.filters,W]),j=Q.useCallback(()=>{W({filters:{},page:1})},[W]);Q.useEffect(()=>{const G=()=>b(Z());window.addEventListener("popstate",G);return()=>window.removeEventListener("popstate",G)},[Z]);return{state:T,setState:W,setFilter:I,clearFilters:j}}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const o=["light","dark"],l={background:["card","popover"],foreground:["card-foreground","popover-foreground"],border:["input"]};function n(e,s){const t=Object.entries(s).sort(([r],[i])=>r.localeCompare(i)).map(([r,i])=>` ${r}: ${i};`).join(`
|
|
2
2
|
`);return`${e} {
|
|
3
|
-
${
|
|
4
|
-
}`}function
|
|
5
|
-
${Object.keys(
|
|
3
|
+
${t}
|
|
4
|
+
}`}function c(e){return Object.assign({},...Object.values(e.modes))}function d(e){if(e.startsWith("--ds-color-"))return`--color-${e.slice(11)}`;if(e.startsWith("--ds-radius-"))return`--radius-${e.slice(12)}`;if(e.startsWith("--ds-space-"))return`--spacing-${e.slice(11)}`;if(e.startsWith("--ds-typography-"))return`--text-${e.slice(16)}`;return}function u(e){if(!e.startsWith("--ds-color-"))return[];const s=e.slice(11);return(l[s]??[]).map((r)=>`--color-${r}`)}function h(e){return`@theme inline {
|
|
5
|
+
${Object.keys(c(e)).sort().flatMap((t)=>{const r=d(t),i=u(t);return[...r?[` ${r}: var(${t});`]:[],...i.map((a)=>` ${a}: var(${t});`)]}).join(`
|
|
6
6
|
`)}
|
|
7
|
-
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([
|
|
7
|
+
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([r])=>!o.includes(r)).map(([r,i])=>n(`[data-theme="${r}"]`,i)),s.includeTheme===!1?void 0:h(e)].filter(Boolean).join(`
|
|
8
8
|
|
|
9
9
|
`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:
|
|
1
|
+
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:D,defaultValue:E,onChange:G,onSubmit:O,onFocus:H,onBlur:J,placeholder:M,disabled:P,readOnly:Q,maxLength:R,name:S,className:U,keyboard:z,componentKey:X,themeVariant:Y,placeholderI18n:Z,ariaLabelI18n:$,...A}){const _=z?B(z):{},q=C({defaultComponentKey:"Input",componentKey:X,themeVariant:Y,className:U,style:A.style,placeholder:M,placeholderI18n:Z,ariaLabelI18n:$});return N(j,{...q.themed.props,..._,...A,className:q.themed.className,style:q.themed.style,value:D,defaultValue:E,onChange:G,onFocus:H,onBlur:J,placeholder:q.placeholder,"aria-label":q.ariaLabel,disabled:P,readOnly:Q,maxLength:R,name:S})}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataViewSpec } from '@contractspec/lib.contracts-spec/data-views';
|
|
1
|
+
import type { DataViewFilterSet, DataViewSpec } from '@contractspec/lib.contracts-spec/data-views';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
export interface DataViewRendererProps {
|
|
4
4
|
spec: DataViewSpec;
|
|
@@ -15,8 +15,8 @@ export interface DataViewRendererProps {
|
|
|
15
15
|
footer?: React.ReactNode;
|
|
16
16
|
search?: string;
|
|
17
17
|
onSearchChange?: (value: string) => void;
|
|
18
|
-
filters?: Record<string, unknown
|
|
19
|
-
onFilterChange?: (filters: Record<string, unknown>) => void;
|
|
18
|
+
filters?: Record<string, unknown> | DataViewFilterSet;
|
|
19
|
+
onFilterChange?: (filters: Record<string, unknown> | DataViewFilterSet) => void;
|
|
20
20
|
pagination?: {
|
|
21
21
|
page: number;
|
|
22
22
|
pageSize: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as J,jsxs as c,Fragment as p}from"react/jsx-runtime";import{resolveDataViewFilters as S}from"@contractspec/lib.contracts-spec/data-views";import{Pagination as d}from"@contractspec/lib.ui-kit-web/ui/atoms/Pagination";import{VStack as h}from"@contractspec/lib.ui-kit-web/ui/stack";import{Text as f}from"@contractspec/lib.ui-kit-web/ui/text";import*as L from"react";import{resolveTranslationString as V,useDesignSystemTranslation as u}from"../../i18n/translation";import{FiltersToolbar as m}from"../molecules/FiltersToolbar";import{DataViewDetail as v}from"./DataViewDetail";import{DataViewList as b}from"./DataViewList";import{DataViewTable as y}from"./DataViewTable";export function DataViewRenderer({spec:B,items:G=[],item:X=null,className:M,renderActions:$,onSelect:q,onRowClick:P,toolbar:R,loading:T,headerActions:Y,emptyState:Q,footer:j,search:w,onSearchChange:_,filters:I,onFilterChange:Z,pagination:K,onPageChange:D}){const z=u(),O=L.useMemo(()=>S({filters:B.view.filters,scope:B.view.filterScope,user:g(I)}),[I,B.view.filterScope,B.view.filters]),N=L.useMemo(()=>{if(B.view.filterScope){const E=Object.entries(O.user).map(([H,W])=>({key:H,label:`${A(B,H)}: ${F(W)}`,onRemove:()=>{const{[H]:r,...C}=O.user;Z?.(C)}})),U=O.lockedChips==="hidden"?[]:Object.entries(O.locked).map(([H,W])=>({key:`locked-${H}`,label:`${A(B,H)}: ${F(W)}`,disabled:!0}));return[...E,...U]}return I?Object.entries(I).map(([E,U])=>({key:E,label:`${E}: ${String(U)}`,onRemove:()=>{const{[E]:H,...W}=I;Z?.(W)}})):[]},[I,Z,O,B]),k=B.view.filterScope?Object.keys(O.user).length>0:Boolean(I&&Object.keys(I).length>0),x=L.useMemo(()=>{switch(B.view.kind){case"list":return J(b,{spec:B,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q});case"table":return J(y,{spec:B,items:G,className:M,onRowClick:P,toolbar:R,loading:T,emptyState:Q,headerActions:Y,footer:j});case"detail":return J(v,{spec:B,item:X,className:M,emptyState:Q,headerActions:Y});case"grid":{const E=B.view,U={kind:"list",layout:"card",fields:E.fields,filters:E.filters,actions:E.actions,primaryField:E.primaryField,secondaryFields:E.secondaryFields,filterScope:E.filterScope},H={...B,view:U};return J(b,{spec:H,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q})}default:return J(f,{className:M,children:V("Unsupported data view kind",z)})}},[B,G,X,M,$,q,P,R,T,Y,Q,j,z]);if(!(B.view.kind==="list"||B.view.kind==="table"||B.view.kind==="grid"))return J(p,{children:x});return c(h,{gap:"lg",children:[(B.view.filters?.length||_||N.length)&&J(m,{searchValue:w,onSearchChange:_,searchPlaceholder:V("Search...",z)??"Search...",activeChips:N,onClearAll:k?()=>Z?.({}):void 0,right:B.view.kind==="table"?void 0:Y}),x,K&&K.total>0&&J(d,{currentPage:K.page,totalPages:Math.ceil(K.total/K.pageSize),totalItems:K.total,itemsPerPage:K.pageSize,onPageChange:(E)=>D?.(E),onItemsPerPageChange:(E)=>{D?.(1)},showItemsPerPage:!1})]})}function g(B){if(!B)return;return Object.fromEntries(Object.entries(B??{}).filter((G)=>Boolean(G[1]&&typeof G[1]==="object"&&"kind"in G[1]&&typeof G[1].kind==="string")))}function A(B,G){return B.view.filters?.find((X)=>X.key===G)?.label??G}function F(B){if(!B)return"";if(B.kind==="single")return String(B.value);if(B.kind==="multi")return B.values.map(String).join(", ");if(B.kind==="range")return[B.from==null?"":String(B.from),B.to==null?"":String(B.to)].filter(Boolean).join(" - ");return`${B.mode}(${B.clauses.length})`}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DataViewSpec } from '@contractspec/lib.contracts-spec/data-views';
|
|
1
|
+
import type { DataViewFilterSet, DataViewSpec } from '@contractspec/lib.contracts-spec/data-views';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
export interface DataViewRendererProps {
|
|
4
4
|
spec: DataViewSpec;
|
|
@@ -15,8 +15,8 @@ export interface DataViewRendererProps {
|
|
|
15
15
|
footer?: React.ReactNode;
|
|
16
16
|
search?: string;
|
|
17
17
|
onSearchChange?: (value: string) => void;
|
|
18
|
-
filters?: Record<string, unknown
|
|
19
|
-
onFilterChange?: (filters: Record<string, unknown>) => void;
|
|
18
|
+
filters?: Record<string, unknown> | DataViewFilterSet;
|
|
19
|
+
onFilterChange?: (filters: Record<string, unknown> | DataViewFilterSet) => void;
|
|
20
20
|
pagination?: {
|
|
21
21
|
page: number;
|
|
22
22
|
pageSize: number;
|
|
@@ -13,5 +13,13 @@ export interface AutocompleteProps extends ThemedPrimitiveProps {
|
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
className?: string;
|
|
15
15
|
emptyText?: string;
|
|
16
|
+
loadingText?: string;
|
|
17
|
+
errorText?: string;
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
error?: string | null;
|
|
20
|
+
id?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
'aria-invalid'?: boolean;
|
|
23
|
+
'aria-describedby'?: string;
|
|
16
24
|
}
|
|
17
|
-
export declare function Autocomplete({ query, options, selectedOptions, onQueryChange, onSelectOption, onRemoveOption, multiple, placeholder, placeholderI18n, readOnly, disabled, className, componentKey, themeVariant, emptyText, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function Autocomplete({ query, options, selectedOptions, onQueryChange, onSelectOption, onRemoveOption, multiple, placeholder, placeholderI18n, readOnly, disabled, className, componentKey, themeVariant, emptyText, loadingText, errorText, loading, error, id, name, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as v}from"react/jsx-runtime";import{Combobox as I}from"@contractspec/lib.ui-kit-web/ui/combobox";import{useThemedPrimitive as T,useTranslatedText as b}from"../../primitives/themed";function H(E){return typeof E==="string"?E:String(E??"")}function g(E,U){const F=new Set,J=[];for(const L of[...U,...E]){const M=H(L.value);if(F.has(M))continue;F.add(M);J.push(L)}return J}export function Autocomplete({query:E,options:U,selectedOptions:F,onQueryChange:J,onSelectOption:L,onRemoveOption:M,multiple:W,placeholder:X,placeholderI18n:Y,readOnly:_,disabled:j,className:q,componentKey:w,themeVariant:D,emptyText:K="No results found.",loadingText:N="Loading options...",errorText:Q="Unable to load options.",loading:R,error:Z,id:S,name:k,"aria-invalid":C,"aria-describedby":B}){const A=b(),$=T({defaultComponentKey:"Autocomplete",componentKey:w,themeVariant:D,className:q}),f=g(U,F),P=new Map(f.map((z)=>[H(z.value),z]));return v(I,{...$.props,id:S,name:k,className:$.className,options:f.map((z)=>({value:H(z.value),label:A(z.labelI18n)??z.labelI18n,description:z.descriptionI18n?A(z.descriptionI18n)??z.descriptionI18n:void 0,disabled:z.disabled})),value:W?void 0:H(F[0]?.value??""),selectedValues:W?F.map((z)=>H(z.value)):void 0,query:E,onQueryChange:J,onValueChange:(z)=>{const G=P.get(z);if(G)L?.(G)},onRemoveValue:(z)=>{const G=P.get(z);if(G)M?.(G)},multiple:W,placeholder:A(Y??X),searchPlaceholder:A(Y??X),emptyText:A(K),loadingText:A(N),errorText:A(Q),loading:R,error:Z?A(Z):null,readOnly:_,disabled:j,"aria-invalid":C,"aria-describedby":B})}
|
|
@@ -13,5 +13,9 @@ export interface AutocompleteProps extends ThemedPrimitiveProps {
|
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
className?: string;
|
|
15
15
|
emptyText?: string;
|
|
16
|
+
loadingText?: string;
|
|
17
|
+
errorText?: string;
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
error?: string | null;
|
|
16
20
|
}
|
|
17
|
-
export declare function Autocomplete({ query, options, selectedOptions, onQueryChange, onSelectOption, onRemoveOption, multiple, placeholder, placeholderI18n, readOnly, disabled, className, componentKey, themeVariant, emptyText, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export declare function Autocomplete({ query, options, selectedOptions, onQueryChange, onSelectOption, onRemoveOption, multiple, placeholder, placeholderI18n, readOnly, disabled, className, componentKey, themeVariant, emptyText, loadingText, errorText, loading, error, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@contractspec/lib.ui-kit-web/ui/select';
|
|
1
|
+
import { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@contractspec/lib.ui-kit-web/ui/select';
|
|
3
2
|
import { type ThemedPrimitiveProps } from '../../primitives/themed';
|
|
3
|
+
import { type FormOption, type SelectOptionGroup } from './select-options';
|
|
4
4
|
export interface SelectProps extends ThemedPrimitiveProps {
|
|
5
|
-
options?: FormOption[];
|
|
5
|
+
options?: readonly FormOption[];
|
|
6
|
+
groups?: readonly SelectOptionGroup[];
|
|
6
7
|
value?: unknown;
|
|
7
8
|
onChange?: (value: unknown) => void;
|
|
8
9
|
placeholder?: string;
|
|
@@ -11,5 +12,6 @@ export interface SelectProps extends ThemedPrimitiveProps {
|
|
|
11
12
|
name?: string;
|
|
12
13
|
className?: string;
|
|
13
14
|
}
|
|
14
|
-
export declare function Select({ options, value, onChange, placeholder, disabled, className, componentKey, themeVariant, placeholderI18n, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
-
export {
|
|
15
|
+
export declare function Select({ options, groups, value, onChange, placeholder, disabled, className, componentKey, themeVariant, placeholderI18n, ...props }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export type { SelectOptionGroup };
|
|
17
|
+
export { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as z,jsxs as M}from"react/jsx-runtime";import{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue,Select as K}from"@contractspec/lib.ui-kit-web/ui/select";import{useThemedPrimitive as O,useTranslatedText as T}from"../../primitives/themed";import{selectGroupKey as v,selectGroupLabel as w,selectOptionGroups as G,selectOptionLabel as L,selectOptionValue as D}from"./select-options";export function Select({options:Q,groups:R,value:E,onChange:U,placeholder:X,disabled:Y,className:Z,componentKey:$,themeVariant:k,placeholderI18n:P,...W}){const B=T(),N=O({defaultComponentKey:"Select",componentKey:$,themeVariant:k,className:Z}),C=G({options:Q,groups:R});return M(K,{value:E==null?"":D(E),onValueChange:(q)=>U?.(q),disabled:Y,...W,children:[z(SelectTrigger,{className:N.className,children:z(SelectValue,{placeholder:B(P??X)})}),z(SelectContent,{children:C.map((q,F)=>{const H=v(q,F),J=w(q,B);return M(SelectGroup,{children:[J?z(SelectLabel,{children:J}):null,q.options.map((A,f)=>z(SelectItem,{value:D(A.value),disabled:A.disabled,children:L(A,B)},`${H}-${D(A.value)}-${f}`))]},`${H}-${F}`)})})]})}export{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@contractspec/lib.ui-kit/ui/select';
|
|
1
|
+
import { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '@contractspec/lib.ui-kit/ui/select';
|
|
3
2
|
import { type ThemedPrimitiveProps } from '../../primitives/themed';
|
|
3
|
+
import { type FormOption, type SelectOptionGroup } from './select-options';
|
|
4
4
|
export interface SelectProps extends ThemedPrimitiveProps {
|
|
5
|
-
options?: FormOption[];
|
|
5
|
+
options?: readonly FormOption[];
|
|
6
|
+
groups?: readonly SelectOptionGroup[];
|
|
6
7
|
value?: unknown;
|
|
7
8
|
onChange?: (value: unknown) => void;
|
|
8
9
|
placeholder?: string;
|
|
9
10
|
disabled?: boolean;
|
|
10
11
|
className?: string;
|
|
11
12
|
}
|
|
12
|
-
export declare function Select({ options, value, onChange, placeholder, disabled, className, componentKey, themeVariant, placeholderI18n, }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export {
|
|
13
|
+
export declare function Select({ options, groups, value, onChange, placeholder, disabled, className, componentKey, themeVariant, placeholderI18n, }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export type { SelectOptionGroup };
|
|
15
|
+
export { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, };
|
|
@@ -9,4 +9,4 @@ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGr
|
|
|
9
9
|
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, } from './InputOTP';
|
|
10
10
|
export { LoadingButton, type LoadingButtonProps } from './LoadingButton';
|
|
11
11
|
export { NativeSelect, NativeSelectOptGroup, NativeSelectOption, type NativeSelectProps, } from './NativeSelect';
|
|
12
|
-
export { Select, type SelectProps } from './Select';
|
|
12
|
+
export { Select, type SelectOptionGroup, type SelectProps } from './Select';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FormOption } from '@contractspec/lib.contracts-spec/forms';
|
|
2
|
+
export type { FormOption };
|
|
3
|
+
export interface SelectOptionGroup {
|
|
4
|
+
key?: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
labelI18n?: string;
|
|
7
|
+
options: readonly FormOption[];
|
|
8
|
+
}
|
|
9
|
+
export type SelectTextTranslator = (value: string | undefined) => string | undefined;
|
|
10
|
+
export declare function selectOptionValue(value: unknown): string;
|
|
11
|
+
export declare function selectOptionLabel(option: FormOption, translate: SelectTextTranslator): string;
|
|
12
|
+
export declare function selectGroupLabel(group: SelectOptionGroup, translate: SelectTextTranslator): string | undefined;
|
|
13
|
+
export declare function selectGroupKey(group: SelectOptionGroup, index: number): string;
|
|
14
|
+
export declare function selectOptionGroups({ options, groups, }: {
|
|
15
|
+
options?: readonly FormOption[];
|
|
16
|
+
groups?: readonly SelectOptionGroup[];
|
|
17
|
+
}): readonly SelectOptionGroup[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function selectOptionValue(e){return typeof e==="string"?e:String(e??"")}export function selectOptionLabel(e,t){return t(e.labelI18n)??selectOptionValue(e.labelI18n)}export function selectGroupLabel(e,t){return t(e.labelI18n??e.label)}export function selectGroupKey(e,t){return e.key??e.labelI18n??e.label??`group-${t}`}export function selectOptionGroups({options:e,groups:t}){return t?.length?t:[{options:e??[]}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as
|
|
1
|
+
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as I}from"@contractspec/lib.ui-kit-web/ui/badge";import{cn as W}from"@contractspec/lib.ui-kit-web/ui/utils";import*as K from"react";import{Button as X}from"../atoms/Button";import{Input as N}from"../atoms/Input";export function FiltersToolbar({className:Y,children:Z,right:$,searchPlaceholder:k,searchValue:G,onSearchChange:F,onSearchSubmit:L,debounceMs:O=250,activeChips:T=[],onClearAll:H}){const[J,U]=K.useState(G??"");K.useEffect(()=>{U(G??"")},[G]);K.useEffect(()=>{if(!F)return;const z=setTimeout(()=>F(J),O);return()=>clearTimeout(z)},[J,O,F]);return D("div",{className:W("space-y-2",Y),children:[D("div",{className:"flex flex-col items-stretch gap-2 md:flex-row md:items-center md:justify-between",children:[D("div",{className:"flex flex-1 items-center gap-2",children:[F?D("div",{className:"flex flex-1 items-center gap-2",children:[E(N,{value:J,onChange:(z)=>U(z.target.value),onKeyDown:(z)=>{if(z.key==="Enter")L?.()},placeholder:k,keyboard:{kind:"search"}}),E(X,{variant:"outline",onPress:()=>L?.(),className:"shrink-0",children:"Rechercher"})]}):null,Z]}),$]}),(T.length>0||H)&&D("div",{className:"flex flex-wrap items-center gap-2",children:[T.map((z)=>D(I,{variant:"secondary",className:W("inline-flex items-center gap-2",z.disabled&&"opacity-70"),children:[E("span",{children:z.label}),z.onRemove&&!z.disabled&&E("button",{type:"button","aria-label":"Supprimer le filtre",onClick:z.onRemove,className:"rounded-xs px-1 text-base hover:bg-muted",children:"\xD7"})]},z.key)),H&&E(X,{size:"sm",variant:"ghost",onPress:H,children:"Effacer les filtres"})]})]})}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ListFilterScope } from '@contractspec/lib.presentation-runtime-core';
|
|
1
2
|
export interface ListUrlState<TFilters extends Record<string, unknown> = Record<string, unknown>> {
|
|
2
3
|
q: string;
|
|
3
4
|
page: number;
|
|
@@ -5,8 +6,9 @@ export interface ListUrlState<TFilters extends Record<string, unknown> = Record<
|
|
|
5
6
|
sort?: string | null;
|
|
6
7
|
filters: TFilters;
|
|
7
8
|
}
|
|
8
|
-
export declare function useListUrlState<TFilters extends Record<string, unknown> = Record<string, unknown>>({ defaults, paramKeys, replaceState, }: {
|
|
9
|
+
export declare function useListUrlState<TFilters extends Record<string, unknown> = Record<string, unknown>>({ defaults, paramKeys, replaceState, filterScope, }: {
|
|
9
10
|
defaults: ListUrlState<TFilters>;
|
|
11
|
+
filterScope?: ListFilterScope<TFilters>;
|
|
10
12
|
paramKeys?: {
|
|
11
13
|
q: string;
|
|
12
14
|
page: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import{createInitialListFilters as N,sanitizeListUserFilters as _}from"@contractspec/lib.presentation-runtime-core";import*as Q from"react";export function useListUrlState({defaults:E,paramKeys:h={q:"q",page:"page",limit:"limit",sort:"sort",filters:"f"},replaceState:$=!0,filterScope:J}){const Y=Q.useMemo(()=>({...N(J),..._(E.filters,J)}),[E.filters,J]),Z=Q.useCallback(()=>{if(typeof window>"u")return E;const A=new URL(window.location.href).searchParams,V=(X,M)=>{const H=X?Number(X):NaN;return Number.isFinite(H)&&H>0?H:M},C=A.get(h.filters);let B=E.filters;if(C)try{B=_(JSON.parse(C),J)}catch{B=Y}else B=Y;return{q:A.get(h.q)??E.q,page:V(A.get(h.page),E.page),limit:V(A.get(h.limit),E.limit),sort:A.get(h.sort),filters:B}},[Y,E,J,h]),[T,b]=Q.useState(Z),W=Q.useCallback((G)=>{if(typeof window>"u")return;const A=new URL(window.location.href),V=A.searchParams,C={...T,...G,filters:_(G.filters??T.filters,J)},B=(M,H)=>{if(H==null||H===""||H==="null")V.delete(M);else V.set(M,H)};B(h.q,C.q||null);B(h.page,String(C.page));B(h.limit,String(C.limit));B(h.sort,C.sort??null);try{const M=JSON.stringify(C.filters??{});B(h.filters,M==="{}"?null:M)}catch{}const X=`${A.pathname}?${V.toString()}${A.hash}`;if($)window.history.replaceState({},"",X);else window.history.pushState({},"",X);b(C)},[J,T,h,$]),I=Q.useCallback((G,A)=>{W({filters:{...T.filters,[G]:A}})},[T.filters,W]),j=Q.useCallback(()=>{W({filters:{},page:1})},[W]);Q.useEffect(()=>{const G=()=>b(Z());window.addEventListener("popstate",G);return()=>window.removeEventListener("popstate",G)},[Z]);return{state:T,setState:W,setFilter:I,clearFilters:j}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:
|
|
1
|
+
import{jsx as N}from"react/jsx-runtime";import{Input as j}from"@contractspec/lib.ui-kit-web/ui/input";import{mapKeyboardToWeb as B}from"../../lib/keyboard";import{useThemedTextField as C}from"../primitives/control";export function Input({value:D,defaultValue:E,onChange:G,onSubmit:O,onFocus:H,onBlur:J,placeholder:M,disabled:P,readOnly:Q,maxLength:R,name:S,className:U,keyboard:z,componentKey:X,themeVariant:Y,placeholderI18n:Z,ariaLabelI18n:$,...A}){const _=z?B(z):{},q=C({defaultComponentKey:"Input",componentKey:X,themeVariant:Y,className:U,style:A.style,placeholder:M,placeholderI18n:Z,ariaLabelI18n:$});return N(j,{...q.themed.props,..._,...A,className:q.themed.className,style:q.themed.style,value:D,defaultValue:E,onChange:G,onFocus:H,onBlur:J,placeholder:q.placeholder,"aria-label":q.ariaLabel,disabled:P,readOnly:Q,maxLength:R,name:S})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as C}from"react/jsx-runtime";import{Input as _}from"@contractspec/lib.ui-kit/ui/input";import{mapKeyboardToNative as j}from"../../lib/keyboard";import{useThemedTextField as B}from"../primitives/control";export function Input({value:
|
|
1
|
+
import{jsx as C}from"react/jsx-runtime";import{Input as _}from"@contractspec/lib.ui-kit/ui/input";import{mapKeyboardToNative as j}from"../../lib/keyboard";import{useThemedTextField as B}from"../primitives/control";export function Input({value:A,defaultValue:D,onChange:E,onSubmit:G,onFocus:H,onBlur:J,placeholder:M,disabled:P,readOnly:Q,maxLength:R,className:U,keyboard:z,componentKey:W,themeVariant:X,placeholderI18n:Y,ariaLabelI18n:Z,...$}){const w=z?j(z):{},q=B({defaultComponentKey:"Input",componentKey:W,themeVariant:X,className:U,placeholder:M,placeholderI18n:Y,ariaLabelI18n:Z});return C(_,{...q.themed.props,...$,className:q.themed.className,value:A,defaultValue:D,onChangeText:E,onSubmitEditing:G,onFocus:H,onBlur:J,placeholder:q.placeholder,accessibilityLabel:q.ariaLabel,editable:!P&&!Q,maxLength:R,...w})}export default Input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as J,jsxs as c,Fragment as p}from"react/jsx-runtime";import{resolveDataViewFilters as S}from"@contractspec/lib.contracts-spec/data-views";import{Pagination as d}from"@contractspec/lib.ui-kit-web/ui/atoms/Pagination";import{VStack as h}from"@contractspec/lib.ui-kit-web/ui/stack";import{Text as f}from"@contractspec/lib.ui-kit-web/ui/text";import*as L from"react";import{resolveTranslationString as V,useDesignSystemTranslation as u}from"../../i18n/translation";import{FiltersToolbar as m}from"../molecules/FiltersToolbar";import{DataViewDetail as v}from"./DataViewDetail";import{DataViewList as b}from"./DataViewList";import{DataViewTable as y}from"./DataViewTable";export function DataViewRenderer({spec:B,items:G=[],item:X=null,className:M,renderActions:$,onSelect:q,onRowClick:P,toolbar:R,loading:T,headerActions:Y,emptyState:Q,footer:j,search:w,onSearchChange:_,filters:I,onFilterChange:Z,pagination:K,onPageChange:D}){const z=u(),O=L.useMemo(()=>S({filters:B.view.filters,scope:B.view.filterScope,user:g(I)}),[I,B.view.filterScope,B.view.filters]),N=L.useMemo(()=>{if(B.view.filterScope){const E=Object.entries(O.user).map(([H,W])=>({key:H,label:`${A(B,H)}: ${F(W)}`,onRemove:()=>{const{[H]:r,...C}=O.user;Z?.(C)}})),U=O.lockedChips==="hidden"?[]:Object.entries(O.locked).map(([H,W])=>({key:`locked-${H}`,label:`${A(B,H)}: ${F(W)}`,disabled:!0}));return[...E,...U]}return I?Object.entries(I).map(([E,U])=>({key:E,label:`${E}: ${String(U)}`,onRemove:()=>{const{[E]:H,...W}=I;Z?.(W)}})):[]},[I,Z,O,B]),k=B.view.filterScope?Object.keys(O.user).length>0:Boolean(I&&Object.keys(I).length>0),x=L.useMemo(()=>{switch(B.view.kind){case"list":return J(b,{spec:B,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q});case"table":return J(y,{spec:B,items:G,className:M,onRowClick:P,toolbar:R,loading:T,emptyState:Q,headerActions:Y,footer:j});case"detail":return J(v,{spec:B,item:X,className:M,emptyState:Q,headerActions:Y});case"grid":{const E=B.view,U={kind:"list",layout:"card",fields:E.fields,filters:E.filters,actions:E.actions,primaryField:E.primaryField,secondaryFields:E.secondaryFields,filterScope:E.filterScope},H={...B,view:U};return J(b,{spec:H,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q})}default:return J(f,{className:M,children:V("Unsupported data view kind",z)})}},[B,G,X,M,$,q,P,R,T,Y,Q,j,z]);if(!(B.view.kind==="list"||B.view.kind==="table"||B.view.kind==="grid"))return J(p,{children:x});return c(h,{gap:"lg",children:[(B.view.filters?.length||_||N.length)&&J(m,{searchValue:w,onSearchChange:_,searchPlaceholder:V("Search...",z)??"Search...",activeChips:N,onClearAll:k?()=>Z?.({}):void 0,right:B.view.kind==="table"?void 0:Y}),x,K&&K.total>0&&J(d,{currentPage:K.page,totalPages:Math.ceil(K.total/K.pageSize),totalItems:K.total,itemsPerPage:K.pageSize,onPageChange:(E)=>D?.(E),onItemsPerPageChange:(E)=>{D?.(1)},showItemsPerPage:!1})]})}function g(B){if(!B)return;return Object.fromEntries(Object.entries(B??{}).filter((G)=>Boolean(G[1]&&typeof G[1]==="object"&&"kind"in G[1]&&typeof G[1].kind==="string")))}function A(B,G){return B.view.filters?.find((X)=>X.key===G)?.label??G}function F(B){if(!B)return"";if(B.kind==="single")return String(B.value);if(B.kind==="multi")return B.values.map(String).join(", ");if(B.kind==="range")return[B.from==null?"":String(B.from),B.to==null?"":String(B.to)].filter(Boolean).join(" - ");return`${B.mode}(${B.clauses.length})`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as J,jsxs as c,Fragment as p}from"react/jsx-runtime";import{resolveDataViewFilters as S}from"@contractspec/lib.contracts-spec/data-views";import{Pagination as d}from"@contractspec/lib.ui-kit/ui/atoms/Pagination";import{VStack as h}from"@contractspec/lib.ui-kit/ui/stack";import{Text as f}from"@contractspec/lib.ui-kit/ui/text";import*as L from"react";import{resolveTranslationString as x,useDesignSystemTranslation as u}from"../../i18n/translation";import{FiltersToolbar as m}from"../molecules/FiltersToolbar";import{DataViewDetail as v}from"./DataViewDetail";import{DataViewList as V}from"./DataViewList";import{DataViewTable as y}from"./DataViewTable";export function DataViewRenderer({spec:B,items:G=[],item:X=null,className:M,renderActions:$,onSelect:q,onRowClick:P,toolbar:R,loading:T,headerActions:Y,emptyState:Q,footer:j,search:w,onSearchChange:_,filters:I,onFilterChange:Z,pagination:K,onPageChange:D}){const z=u(),O=L.useMemo(()=>S({filters:B.view.filters,scope:B.view.filterScope,user:g(I)}),[I,B.view.filterScope,B.view.filters]),N=L.useMemo(()=>{if(B.view.filterScope){const E=Object.entries(O.user).map(([H,W])=>({key:H,label:`${A(B,H)}: ${F(W)}`,onRemove:()=>{const{[H]:r,...C}=O.user;Z?.(C)}})),U=O.lockedChips==="hidden"?[]:Object.entries(O.locked).map(([H,W])=>({key:`locked-${H}`,label:`${A(B,H)}: ${F(W)}`,disabled:!0}));return[...E,...U]}return I?Object.entries(I).map(([E,U])=>({key:E,label:`${E}: ${String(U)}`,onRemove:()=>{const{[E]:H,...W}=I;Z?.(W)}})):[]},[I,Z,O,B]),k=B.view.filterScope?Object.keys(O.user).length>0:Boolean(I&&Object.keys(I).length>0),b=L.useMemo(()=>{switch(B.view.kind){case"list":return J(V,{spec:B,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q});case"table":return J(y,{spec:B,items:G,className:M,onRowClick:P,toolbar:R,loading:T,emptyState:Q,headerActions:Y,footer:j});case"detail":return J(v,{spec:B,item:X,className:M,emptyState:Q,headerActions:Y});case"grid":{const E=B.view,U={kind:"list",layout:"card",fields:E.fields,filters:E.filters,actions:E.actions,primaryField:E.primaryField,secondaryFields:E.secondaryFields,filterScope:E.filterScope},H={...B,view:U};return J(V,{spec:H,items:G,className:M,renderActions:$,onSelect:q,emptyState:Q})}default:return J(f,{className:M,children:x("Unsupported data view kind",z)})}},[B,G,X,M,$,q,P,R,T,Y,Q,j,z]);if(!(B.view.kind==="list"||B.view.kind==="table"||B.view.kind==="grid"))return J(p,{children:b});return c(h,{gap:"lg",children:[(B.view.filters?.length||_||N.length)&&J(m,{searchValue:w,onSearchChange:_,searchPlaceholder:x("Search...",z)??"Search...",activeChips:N,onClearAll:k?()=>Z?.({}):void 0,right:B.view.kind==="table"?void 0:Y}),b,K&&K.total>0?J(d,{currentPage:K.page,totalPages:Math.ceil(K.total/K.pageSize),totalItems:K.total,itemsPerPage:K.pageSize,onPageChange:(E)=>D?.(E),onItemsPerPageChange:(E)=>{D?.(1)},showItemsPerPage:!1}):null]})}function g(B){if(!B)return;return Object.fromEntries(Object.entries(B??{}).filter((G)=>Boolean(G[1]&&typeof G[1]==="object"&&"kind"in G[1]&&typeof G[1].kind==="string")))}function A(B,G){return B.view.filters?.find((X)=>X.key===G)?.label??G}function F(B){if(!B)return"";if(B.kind==="single")return String(B.value);if(B.kind==="multi")return B.values.map(String).join(", ");if(B.kind==="range")return[B.from==null?"":String(B.from),B.to==null?"":String(B.to)].filter(Boolean).join(" - ");return`${B.mode}(${B.clauses.length})`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as v}from"react/jsx-runtime";import{Combobox as I}from"@contractspec/lib.ui-kit-web/ui/combobox";import{useThemedPrimitive as T,useTranslatedText as b}from"../../primitives/themed";function H(E){return typeof E==="string"?E:String(E??"")}function g(E,U){const F=new Set,J=[];for(const L of[...U,...E]){const M=H(L.value);if(F.has(M))continue;F.add(M);J.push(L)}return J}export function Autocomplete({query:E,options:U,selectedOptions:F,onQueryChange:J,onSelectOption:L,onRemoveOption:M,multiple:W,placeholder:X,placeholderI18n:Y,readOnly:_,disabled:j,className:q,componentKey:w,themeVariant:D,emptyText:K="No results found.",loadingText:N="Loading options...",errorText:Q="Unable to load options.",loading:R,error:Z,id:S,name:k,"aria-invalid":C,"aria-describedby":B}){const A=b(),$=T({defaultComponentKey:"Autocomplete",componentKey:w,themeVariant:D,className:q}),f=g(U,F),P=new Map(f.map((z)=>[H(z.value),z]));return v(I,{...$.props,id:S,name:k,className:$.className,options:f.map((z)=>({value:H(z.value),label:A(z.labelI18n)??z.labelI18n,description:z.descriptionI18n?A(z.descriptionI18n)??z.descriptionI18n:void 0,disabled:z.disabled})),value:W?void 0:H(F[0]?.value??""),selectedValues:W?F.map((z)=>H(z.value)):void 0,query:E,onQueryChange:J,onValueChange:(z)=>{const G=P.get(z);if(G)L?.(G)},onRemoveValue:(z)=>{const G=P.get(z);if(G)M?.(G)},multiple:W,placeholder:A(Y??X),searchPlaceholder:A(Y??X),emptyText:A(K),loadingText:A(N),errorText:A(Q),loading:R,error:Z?A(Z):null,readOnly:_,disabled:j,"aria-invalid":C,"aria-describedby":B})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as A,jsxs as
|
|
1
|
+
import{jsx as A,jsxs as w}from"react/jsx-runtime";import{Text as F}from"@contractspec/lib.ui-kit/ui/text";import{Button as W}from"../../atoms/Button";import{Input as S}from"../../atoms/Input";import{HStack as V,VStack as X}from"../../layout/Stack";import{useThemedPrimitive as b,useTranslatedText as f}from"../../primitives/themed";function Y(E){return typeof E==="string"?E:String(E??"")}export function Autocomplete({query:E,options:L,selectedOptions:M,onQueryChange:Z,onSelectOption:$,onRemoveOption:H,multiple:P,placeholder:q,placeholderI18n:C,readOnly:G,disabled:J,className:K,componentKey:N,themeVariant:Q,emptyText:R="No results found.",loadingText:B="Loading options...",errorText:I="Unable to load options.",loading:k,error:U}){const D=f(),g=b({defaultComponentKey:"Autocomplete",componentKey:N,themeVariant:Q,className:K});return w(X,{gap:"sm",className:g.className,children:[A(S,{value:E,onChange:(z)=>{if(typeof z==="string")Z?.(z)},placeholder:D(C??q),disabled:J||G}),A(X,{gap:"xs",children:k?A(F,{children:D(B)}):U?A(F,{children:D(U)??D(I)}):L.length?L.map((z)=>A(W,{variant:"ghost",onPress:()=>$?.(z),disabled:J||z.disabled||G,children:A(F,{children:D(z.labelI18n)})},Y(z.value))):A(F,{children:D(R)})}),M.length?A(V,{gap:"sm",wrap:"wrap",children:M.map((z)=>A(W,{variant:"outline",size:"sm",onPress:()=>H?.(z),disabled:!P||G||J,children:A(F,{children:D(z.labelI18n)})},`selected-${Y(z.value)}`))}):null]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as z,jsxs as M}from"react/jsx-runtime";import{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue,Select as K}from"@contractspec/lib.ui-kit-web/ui/select";import{useThemedPrimitive as O,useTranslatedText as T}from"../../primitives/themed";import{selectGroupKey as v,selectGroupLabel as w,selectOptionGroups as G,selectOptionLabel as L,selectOptionValue as D}from"./select-options";export function Select({options:Q,groups:R,value:E,onChange:U,placeholder:X,disabled:Y,className:Z,componentKey:$,themeVariant:k,placeholderI18n:P,...W}){const B=T(),N=O({defaultComponentKey:"Select",componentKey:$,themeVariant:k,className:Z}),C=G({options:Q,groups:R});return M(K,{value:E==null?"":D(E),onValueChange:(q)=>U?.(q),disabled:Y,...W,children:[z(SelectTrigger,{className:N.className,children:z(SelectValue,{placeholder:B(P??X)})}),z(SelectContent,{children:C.map((q,F)=>{const H=v(q,F),J=w(q,B);return M(SelectGroup,{children:[J?z(SelectLabel,{children:J}):null,q.options.map((A,f)=>z(SelectItem,{value:D(A.value),disabled:A.disabled,children:L(A,B)},`${H}-${D(A.value)}-${f}`))]},`${H}-${F}`)})})]})}export{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as B,jsxs as
|
|
1
|
+
import{jsx as B,jsxs as X}from"react/jsx-runtime";import{Select as v,SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue}from"@contractspec/lib.ui-kit/ui/select";import{useThemedPrimitive as G,useTranslatedText as _}from"../../primitives/themed";import{selectGroupKey as L,selectGroupLabel as j,selectOptionGroups as y,selectOptionLabel as W,selectOptionValue as A}from"./select-options";export function Select({options:Y,groups:Z,value:H,onChange:$,placeholder:k,disabled:P,className:R,componentKey:N,themeVariant:C,placeholderI18n:f}){const D=_(),w=G({defaultComponentKey:"Select",componentKey:N,themeVariant:C,className:R}),J=y({options:Y,groups:Z}),z=H==null?void 0:A(H),F=J.flatMap((q)=>q.options).find((q)=>A(q.value)===z),K=F?W(F,D)??A(F.value):z;return X(v,{value:z==null?void 0:{value:z,label:K??z},onValueChange:(q)=>$?.(q?.value),children:[B(SelectTrigger,{disabled:P,className:w.className,children:B(SelectValue,{placeholder:D(f??k)??""})}),B(SelectContent,{children:J.map((q,M)=>{const Q=L(q,M),U=j(q,D);return X(SelectGroup,{children:[U?B(SelectLabel,{children:U}):null,q.options.map((E,T)=>B(SelectItem,{value:A(E.value),label:W(E,D),disabled:E.disabled},`${Q}-${A(E.value)}-${T}`))]},`${Q}-${M}`)})})]})}export{SelectContent,SelectGroup,SelectItem,SelectLabel,SelectTrigger,SelectValue};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function selectOptionValue(e){return typeof e==="string"?e:String(e??"")}export function selectOptionLabel(e,t){return t(e.labelI18n)??selectOptionValue(e.labelI18n)}export function selectGroupLabel(e,t){return t(e.labelI18n??e.label)}export function selectGroupKey(e,t){return e.key??e.labelI18n??e.label??`group-${t}`}export function selectOptionGroups({options:e,groups:t}){return t?.length?t:[{options:e??[]}]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as
|
|
1
|
+
import{jsx as E,jsxs as D}from"react/jsx-runtime";import{Badge as I}from"@contractspec/lib.ui-kit-web/ui/badge";import{cn as W}from"@contractspec/lib.ui-kit-web/ui/utils";import*as K from"react";import{Button as X}from"../atoms/Button";import{Input as N}from"../atoms/Input";export function FiltersToolbar({className:Y,children:Z,right:$,searchPlaceholder:k,searchValue:G,onSearchChange:F,onSearchSubmit:L,debounceMs:O=250,activeChips:T=[],onClearAll:H}){const[J,U]=K.useState(G??"");K.useEffect(()=>{U(G??"")},[G]);K.useEffect(()=>{if(!F)return;const z=setTimeout(()=>F(J),O);return()=>clearTimeout(z)},[J,O,F]);return D("div",{className:W("space-y-2",Y),children:[D("div",{className:"flex flex-col items-stretch gap-2 md:flex-row md:items-center md:justify-between",children:[D("div",{className:"flex flex-1 items-center gap-2",children:[F?D("div",{className:"flex flex-1 items-center gap-2",children:[E(N,{value:J,onChange:(z)=>U(z.target.value),onKeyDown:(z)=>{if(z.key==="Enter")L?.()},placeholder:k,keyboard:{kind:"search"}}),E(X,{variant:"outline",onPress:()=>L?.(),className:"shrink-0",children:"Rechercher"})]}):null,Z]}),$]}),(T.length>0||H)&&D("div",{className:"flex flex-wrap items-center gap-2",children:[T.map((z)=>D(I,{variant:"secondary",className:W("inline-flex items-center gap-2",z.disabled&&"opacity-70"),children:[E("span",{children:z.label}),z.onRemove&&!z.disabled&&E("button",{type:"button","aria-label":"Supprimer le filtre",onClick:z.onRemove,className:"rounded-xs px-1 text-base hover:bg-muted",children:"×"})]},z.key)),H&&E(X,{size:"sm",variant:"ghost",onPress:H,children:"Effacer les filtres"})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as E,jsxs as F}from"react/jsx-runtime";import{HStack as L,VStack as P}from"@contractspec/lib.ui-kit/ui/stack";import*as O from"react";import{Button as T}from"../atoms/Button";import{Input as Q}from"../atoms/Input";export function FiltersToolbar({className:Y,children:Z,right:$,searchPlaceholder:I,searchValue:G,onSearchChange:D,onSearchSubmit:N,debounceMs:U=250,activeChips:W=[],onClearAll:J}){const[K,X]=O.useState(G??"");O.useEffect(()=>{X(G??"")},[G]);O.useEffect(()=>{if(!D)return;const z=setTimeout(()=>D(K),U);return()=>clearTimeout(z)},[K,U,D]);return F(P,{className:Y,children:[F(L,{className:"items-center gap-2",children:[D?F(L,{className:"flex-1 items-center gap-2",children:[E(Q,{value:K,onChange:(z)=>X(z.target.value),placeholder:I,keyboard:{kind:"search"}}),E(T,{variant:"outline",onPress:()=>N?.(),children:"Rechercher"})]}):null,Z,$]}),(W.length>0||J)&&F(L,{className:"mt-2 flex flex-wrap items-center gap-2",children:[W.map((z)=>E(T,{size:"sm",variant:"secondary",onPress:z.onRemove,children:z.label},z.key)),J?E(T,{size:"sm",variant:"ghost",onPress:J,children:"Effacer les filtres"}):null]})]})}
|
|
1
|
+
import{jsx as E,jsxs as F}from"react/jsx-runtime";import{HStack as L,VStack as P}from"@contractspec/lib.ui-kit/ui/stack";import*as O from"react";import{Button as T}from"../atoms/Button";import{Input as Q}from"../atoms/Input";export function FiltersToolbar({className:Y,children:Z,right:$,searchPlaceholder:I,searchValue:G,onSearchChange:D,onSearchSubmit:N,debounceMs:U=250,activeChips:W=[],onClearAll:J}){const[K,X]=O.useState(G??"");O.useEffect(()=>{X(G??"")},[G]);O.useEffect(()=>{if(!D)return;const z=setTimeout(()=>D(K),U);return()=>clearTimeout(z)},[K,U,D]);return F(P,{className:Y,children:[F(L,{className:"items-center gap-2",children:[D?F(L,{className:"flex-1 items-center gap-2",children:[E(Q,{value:K,onChange:(z)=>X(z.target.value),placeholder:I,keyboard:{kind:"search"}}),E(T,{variant:"outline",onPress:()=>N?.(),children:"Rechercher"})]}):null,Z,$]}),(W.length>0||J)&&F(L,{className:"mt-2 flex flex-wrap items-center gap-2",children:[W.map((z)=>E(T,{size:"sm",variant:"secondary",disabled:z.disabled,onPress:z.disabled?void 0:z.onRemove,children:z.label},z.key)),J?E(T,{size:"sm",variant:"ghost",onPress:J,children:"Effacer les filtres"}):null]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import{createInitialListFilters as N,sanitizeListUserFilters as _}from"@contractspec/lib.presentation-runtime-core";import*as Q from"react";export function useListUrlState({defaults:E,paramKeys:h={q:"q",page:"page",limit:"limit",sort:"sort",filters:"f"},replaceState:$=!0,filterScope:J}){const Y=Q.useMemo(()=>({...N(J),..._(E.filters,J)}),[E.filters,J]),Z=Q.useCallback(()=>{if(typeof window>"u")return E;const A=new URL(window.location.href).searchParams,V=(X,M)=>{const H=X?Number(X):NaN;return Number.isFinite(H)&&H>0?H:M},C=A.get(h.filters);let B=E.filters;if(C)try{B=_(JSON.parse(C),J)}catch{B=Y}else B=Y;return{q:A.get(h.q)??E.q,page:V(A.get(h.page),E.page),limit:V(A.get(h.limit),E.limit),sort:A.get(h.sort),filters:B}},[Y,E,J,h]),[T,b]=Q.useState(Z),W=Q.useCallback((G)=>{if(typeof window>"u")return;const A=new URL(window.location.href),V=A.searchParams,C={...T,...G,filters:_(G.filters??T.filters,J)},B=(M,H)=>{if(H==null||H===""||H==="null")V.delete(M);else V.set(M,H)};B(h.q,C.q||null);B(h.page,String(C.page));B(h.limit,String(C.limit));B(h.sort,C.sort??null);try{const M=JSON.stringify(C.filters??{});B(h.filters,M==="{}"?null:M)}catch{}const X=`${A.pathname}?${V.toString()}${A.hash}`;if($)window.history.replaceState({},"",X);else window.history.pushState({},"",X);b(C)},[J,T,h,$]),I=Q.useCallback((G,A)=>{W({filters:{...T.filters,[G]:A}})},[T.filters,W]),j=Q.useCallback(()=>{W({filters:{},page:1})},[W]);Q.useEffect(()=>{const G=()=>b(Z());window.addEventListener("popstate",G);return()=>window.removeEventListener("popstate",G)},[Z]);return{state:T,setState:W,setFilter:I,clearFilters:j}}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const o=["light","dark"],l={background:["card","popover"],foreground:["card-foreground","popover-foreground"],border:["input"]};function n(e,s){const t=Object.entries(s).sort(([r],[i])=>r.localeCompare(i)).map(([r,i])=>` ${r}: ${i};`).join(`
|
|
2
2
|
`);return`${e} {
|
|
3
|
-
${
|
|
4
|
-
}`}function
|
|
5
|
-
${Object.keys(
|
|
3
|
+
${t}
|
|
4
|
+
}`}function c(e){return Object.assign({},...Object.values(e.modes))}function d(e){if(e.startsWith("--ds-color-"))return`--color-${e.slice(11)}`;if(e.startsWith("--ds-radius-"))return`--radius-${e.slice(12)}`;if(e.startsWith("--ds-space-"))return`--spacing-${e.slice(11)}`;if(e.startsWith("--ds-typography-"))return`--text-${e.slice(16)}`;return}function u(e){if(!e.startsWith("--ds-color-"))return[];const s=e.slice(11);return(l[s]??[]).map((r)=>`--color-${r}`)}function h(e){return`@theme inline {
|
|
5
|
+
${Object.keys(c(e)).sort().flatMap((t)=>{const r=d(t),i=u(t);return[...r?[` ${r}: var(${t});`]:[],...i.map((a)=>` ${a}: var(${t});`)]}).join(`
|
|
6
6
|
`)}
|
|
7
|
-
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([
|
|
7
|
+
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([r])=>!o.includes(r)).map(([r,i])=>n(`[data-theme="${r}"]`,i)),s.includeTheme===!1?void 0:h(e)].filter(Boolean).join(`
|
|
8
8
|
|
|
9
9
|
`)}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const o=["light","dark"];const l={background:["card","popover"],foreground:["card-foreground","popover-foreground"],border:["input"]};function n(e,s){const t=Object.entries(s).sort(([r],[i])=>r.localeCompare(i)).map(([r,i])=>` ${r}: ${i};`).join(`
|
|
2
2
|
`);return`${e} {
|
|
3
|
-
${
|
|
4
|
-
}`}function
|
|
5
|
-
${Object.keys(
|
|
3
|
+
${t}
|
|
4
|
+
}`}function c(e){return Object.assign({},...Object.values(e.modes))}function d(e){if(e.startsWith("--ds-color-"))return`--color-${e.slice(11)}`;if(e.startsWith("--ds-radius-"))return`--radius-${e.slice(12)}`;if(e.startsWith("--ds-space-"))return`--spacing-${e.slice(11)}`;if(e.startsWith("--ds-typography-"))return`--text-${e.slice(16)}`;return}function u(e){if(!e.startsWith("--ds-color-"))return[];const s=e.slice(11);return(l[s]??[]).map((r)=>`--color-${r}`)}function h(e){return`@theme inline {
|
|
5
|
+
${Object.keys(c(e)).sort().flatMap((t)=>{const r=d(t),i=u(t);return[...r?[` ${r}: var(${t});`]:[],...i.map((a)=>` ${a}: var(${t});`)]}).join(`
|
|
6
6
|
`)}
|
|
7
|
-
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([
|
|
7
|
+
}`}export function themeSpecToTailwindCss(e,s={}){return[s.includeCustomVariant?"@custom-variant dark (&:where(.dark, .dark *));":void 0,n(s.rootSelector??":root",e.light),n(s.darkSelector??".dark",e.dark),...Object.entries(e.modes).filter(([r])=>!o.includes(r)).map(([r,i])=>n(`[data-theme="${r}"]`,i)),s.includeTheme===!1?void 0:h(e)].filter(Boolean).join(`
|
|
8
8
|
|
|
9
9
|
`)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.design-system",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Design tokens and theming primitives",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"sideEffects": false,
|
|
32
32
|
"tree-shake": true,
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@contractspec/lib.ai-agent": "8.0.
|
|
35
|
-
"@contractspec/lib.contracts-spec": "
|
|
36
|
-
"@contractspec/lib.contracts-runtime-client-react": "3.
|
|
37
|
-
"@contractspec/lib.presentation-runtime-react": "
|
|
38
|
-
"@contractspec/lib.ui-kit": "4.1.
|
|
39
|
-
"@contractspec/lib.ui-kit-web": "3.
|
|
34
|
+
"@contractspec/lib.ai-agent": "8.0.13",
|
|
35
|
+
"@contractspec/lib.contracts-spec": "6.0.0",
|
|
36
|
+
"@contractspec/lib.contracts-runtime-client-react": "3.12.0",
|
|
37
|
+
"@contractspec/lib.presentation-runtime-react": "39.0.1",
|
|
38
|
+
"@contractspec/lib.ui-kit": "4.1.2",
|
|
39
|
+
"@contractspec/lib.ui-kit-web": "3.13.0",
|
|
40
40
|
"@hookform/resolvers": "5.2.2",
|
|
41
41
|
"class-variance-authority": "^0.7.1",
|
|
42
42
|
"clsx": "^2.1.1",
|
|
@@ -464,6 +464,12 @@
|
|
|
464
464
|
"bun": "./dist/components/forms/controls/Select.js",
|
|
465
465
|
"default": "./dist/components/forms/controls/Select.js"
|
|
466
466
|
},
|
|
467
|
+
"./components/forms/controls/select-options": {
|
|
468
|
+
"types": "./dist/components/forms/controls/select-options.d.ts",
|
|
469
|
+
"browser": "./dist/browser/components/forms/controls/select-options.js",
|
|
470
|
+
"bun": "./dist/components/forms/controls/select-options.js",
|
|
471
|
+
"default": "./dist/components/forms/controls/select-options.js"
|
|
472
|
+
},
|
|
467
473
|
"./components/forms/controls/Select.native": {
|
|
468
474
|
"types": "./dist/components/forms/controls/Select.native.d.ts",
|
|
469
475
|
"react-native": "./dist/native/components/forms/controls/Select.native.js",
|
|
@@ -2019,6 +2025,12 @@
|
|
|
2019
2025
|
"bun": "./dist/components/forms/controls/Select.js",
|
|
2020
2026
|
"default": "./dist/components/forms/controls/Select.js"
|
|
2021
2027
|
},
|
|
2028
|
+
"./components/forms/controls/select-options": {
|
|
2029
|
+
"types": "./dist/components/forms/controls/select-options.d.ts",
|
|
2030
|
+
"browser": "./dist/browser/components/forms/controls/select-options.js",
|
|
2031
|
+
"bun": "./dist/components/forms/controls/select-options.js",
|
|
2032
|
+
"default": "./dist/components/forms/controls/select-options.js"
|
|
2033
|
+
},
|
|
2022
2034
|
"./components/forms/controls/Select.native": {
|
|
2023
2035
|
"types": "./dist/components/forms/controls/Select.native.d.ts",
|
|
2024
2036
|
"react-native": "./dist/native/components/forms/controls/Select.native.js",
|