@clicktap/ui 1.2.1 → 2.0.3
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/components/Accordion/Accordion.d.ts +76 -2
- package/components/Accordion/Accordion.js +1 -1
- package/components/Accordion/index.d.ts +2 -3
- package/components/Accordion/index.js +1 -1
- package/components/Badge/Badge.js +1 -1
- package/components/Badge/Badge.types.d.ts +27 -2
- package/components/Badge/index.js +1 -1
- package/components/Collapsible/Collapsible.js +1 -1
- package/components/Collection/CollectionFilters/CollectionFilters.js +1 -1
- package/components/Collection/CollectionFilters/index.js +1 -1
- package/components/Collection/index.js +1 -1
- package/components/ContextMenu/ContextMenu.js +1 -1
- package/components/DialogTrigger/DialogTrigger.d.ts +18 -10
- package/components/DialogTrigger/DialogTrigger.js +1 -1
- package/components/DialogTrigger/index.js +1 -1
- package/components/Drawer/Drawer.js +1 -1
- package/components/Menu/Menu.js +1 -1
- package/components/Meter/Meter.js +1 -1
- package/components/NumberTicker/DigitResolver.js +1 -1
- package/components/NumberTicker/NumberTicker.js +1 -1
- package/components/Pagination/Pagination.d.ts +27 -2
- package/components/Pagination/Pagination.js +1 -1
- package/components/Pagination/index.js +1 -1
- package/components/Progressbar/LinearProgressbar.js +1 -1
- package/components/Tabs/Tab.js +1 -1
- package/components/Tooltip/Tooltip.d.ts +9 -1
- package/components/Tooltip/Tooltip.js +1 -1
- package/components/Tooltip/Tooltip.types.d.ts +21 -2
- package/components/Tooltip/index.js +1 -1
- package/components/UploadImage/UploadImage.js +1 -1
- package/docs/migrations/2026/08/ui-2026-08-21-graphql-client-string-documents.md +45 -0
- package/docs/migrations/2026/08/ui-2026-08-21-graphql-peer-covered.md +26 -0
- package/docs/migrations/2026/08/ui-2026-08-21-heroui-removed.md +54 -0
- package/docs/migrations/2026/08/ui-2026-08-21-lazymotion-m-components.md +54 -0
- package/docs/migrations/2026/08/ui-2026-08-21-modal-triggers-wired-explicitly.md +43 -0
- package/docs/migrations/2026/08/ui-2026-08-21-next-image-fallback-keeps-fill.md +38 -0
- package/docs/migrations/2026/08/ui-2026-08-22-accordion-divider-between-items.md +30 -0
- package/docs/migrations/2026/08/ui-2026-08-22-accordion-divider-class-ownership.md +14 -0
- package/docs/migrations/2026/08/ui-2026-08-22-react-aria-moves-as-one-version-set.md +46 -0
- package/docs/migrations/index.json +91 -0
- package/next/Image.js +1 -1
- package/package.json +10 -38
- package/utils/createAuthAwareGraphqlClient.d.ts +104 -16
- package/utils/createAuthAwareGraphqlClient.js +1 -56
|
@@ -1,3 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Native pagination (CTAP-1383) — previously a styled wrapper around
|
|
3
|
+
* @heroui/pagination, the last @heroui consumer in this library. Standard
|
|
4
|
+
* boundary/sibling windowing with ellipses; heroui prop names kept for the
|
|
5
|
+
* call sites this repo uses (total, page/initialPage, onChange, boundaries,
|
|
6
|
+
* siblings, showControls, className, classNames).
|
|
7
|
+
*/
|
|
8
|
+
export type PaginationProps = {
|
|
9
|
+
total: number;
|
|
10
|
+
page?: number;
|
|
11
|
+
initialPage?: number;
|
|
12
|
+
onChange?: (page: number) => void;
|
|
13
|
+
boundaries?: number;
|
|
14
|
+
siblings?: number;
|
|
15
|
+
showControls?: boolean;
|
|
16
|
+
isCompact?: boolean;
|
|
17
|
+
isDisabled?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
classNames?: {
|
|
20
|
+
wrapper?: string;
|
|
21
|
+
item?: string;
|
|
22
|
+
prev?: string;
|
|
23
|
+
next?: string;
|
|
24
|
+
ellipsis?: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export declare function Pagination({ total, page, initialPage, onChange, boundaries, siblings, showControls, isCompact, isDisabled, className, classNames, }: PaginationProps): import("react/jsx-runtime").JSX.Element;
|
|
3
28
|
export default Pagination;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as a,jsxs as N}from"react/jsx-runtime";import{useState as j}from"react";import{cn as l}from"../../utils/cn.js";import{DownArrow as v}from"../Icon/DownArrow.js";const g=l("w-8 h-8 flex justify-center items-center cursor-pointer shadow-none","border border-solid border-border-subtle data-[disabled=true]:border-0","rounded transition-colors duration-300 focus-visible:outline-white focus-visible:outline-offset-4","bg-transparent hover:bg-slate-50 data-[disabled=true]:bg-surface-subtle data-[disabled=true]:text-fg-subtle","[&>svg]:w-4.5 [&>svg]:h-auto");function M(e,h,t,d){const s=(b,n)=>Array.from({length:n-b+1},(m,o)=>b+o);if(e<=t*2+d*2+3)return s(1,e);const f=Math.max(h-d,t+2),c=Math.min(h+d,e-t-1);return[...s(1,t),f>t+2?"ellipsis":t+1,...s(f,c),c<e-t-1?"ellipsis":e-t,...s(e-t+1,e)]}function $({total:e,page:h,initialPage:t=1,onChange:d,boundaries:s=1,siblings:f=1,showControls:c=!0,isCompact:b=!1,isDisabled:n,className:m,classNames:o}){const[w,x]=j(t),r=h??w,p=i=>{const u=Math.min(Math.max(i,1),e);u!==r&&(x(u),d?.(u))};return a("nav",{"aria-label":"Pagination",className:l("text-slate-600",m),children:N("ul",{className:l("flex flex-nowrap gap-2 lg:gap-3 list-none p-0 m-0",o?.wrapper),children:[c&&a("li",{children:a("button",{type:"button","aria-label":"Previous page",disabled:n||r<=1,"data-disabled":n||r<=1||void 0,onClick:()=>p(r-1),className:l(g,o?.prev),children:a(v,{className:"rotate-90 w-4 h-4"})})}),M(e,r,s,f).map((i,u)=>i==="ellipsis"?a("li",{"aria-hidden":"true",className:l("w-4 h-4.5 scale-110 translate-y-1",o?.ellipsis),children:"…"},`e-${u}`):a("li",{children:a("button",{type:"button","aria-label":`Page ${i}`,"aria-current":i===r?"page":void 0,disabled:n,"data-active":i===r||void 0,onClick:()=>p(i),className:l(b?"w-6 h-6 text-xs":"w-8 h-8 text-sm","flex justify-center items-center cursor-pointer rounded shadow-none","border-solid border border-slate-100 bg-transparent transition-colors duration-300","data-[active=true]:bg-slate-500 data-[active=true]:text-white focus-visible:outline-white focus-visible:outline-offset-4","hover:not-data-[active=true]:border-border-subtle",o?.item),children:i})},i)),c&&a("li",{children:a("button",{type:"button","aria-label":"Next page",disabled:n||r>=e,"data-disabled":n||r>=e||void 0,onClick:()=>p(r+1),className:l(g,o?.next),children:a(v,{className:"-rotate-90 w-4 h-4"})})})]})})}export{$ as Pagination,$ as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Pagination as
|
|
1
|
+
import{Pagination as a}from"./Pagination.js";import"react/jsx-runtime";import"react";import"../../utils/cn.js";import"../Icon/DownArrow.js";export{a as Pagination};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t,jsxs as i,Fragment as m}from"react/jsx-runtime";import{ProgressBar as u,Label as h}from"react-aria-components";import{
|
|
1
|
+
"use client";import{jsx as t,jsxs as i,Fragment as m}from"react/jsx-runtime";import{ProgressBar as u,Label as h}from"react-aria-components";import{m as p}from"framer-motion";import{cn as r}from"../../utils/cn.js";function g({label:a,isIndeterminate:n,showValue:l=!0,width:d,className:s,classNames:e,...c}){return t(u,{style:{width:d||"100%"},className:r("overflow-hidden",s),...c,children:({percentage:o,valueText:f})=>i(m,{children:[i("div",{className:r("flex items-center justify-between gap-2 mb-1",e?.labelWrapper),children:[t(h,{className:r("text-sm",e?.label),children:a}),l&&t("span",{className:r("text-sm",e?.value),children:f})]}),t("div",{className:r("overflow-hidden forced-color-adjust-none h-2.5 rounded will-change-transform bg-slate-300",e?.trackWrapper),children:t(p.div,{style:{width:!n&&typeof o=="number"?`${o}%`:""},...n&&{animate:{x:["-100%","250px"]},transition:{repeat:1/0,duration:1.5}},className:r("h-full bg-surface-inverse-hover rounded transition-width duration-500 ease-in-out",{"w-1/2":n,"transition-none":n},e?.track)})})]})})}export{g as LinearProgressbar,g as default};
|
package/components/Tabs/Tab.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as d,jsxs as u,Fragment as c}from"react/jsx-runtime";import{useContext as b}from"react";import{Tab as f}from"react-aria-components";import{
|
|
1
|
+
"use client";import{jsx as d,jsxs as u,Fragment as c}from"react/jsx-runtime";import{useContext as b}from"react";import{Tab as f}from"react-aria-components";import{m}from"framer-motion";import{cn as i}from"../../utils/cn.js";import{TabsOrientationContext as p}from"./Tabs.context.js";function x({orientation:o,variant:e="base",className:l,children:t,...r}){return d(f,{className:i("flex items-center relative z-10","text-sm cursor-pointer forced-color-adjust-none","transition-all duration-300 ease-in-out","justify-center","disabled:opacity-50","selected:outline-0 hover:outline-0 hover:text-fg-muted",e==="underline"&&o==="vertical"&&"justify-start","py-2 px-3",e==="underline"&&o==="horizontal"&&"p-3",e==="underline"&&o==="vertical"&&"py-3 pr-3 pl-0",(e==="underline"||e==="outline"||e==="enclosed")&&"text-slate-800",e==="solid"&&"text-fg-subtle",(e==="underline"||e==="outline")&&"selected:text-slate-800",(e==="solid"||e==="enclosed")&&"selected:text-slate-100",l),...r,children:t})}function w({variant:o="base",children:e,className:l,classNames:t,...r}){const s=b(p);return d(x,{orientation:s,variant:o,className:l,...r,children:n=>u(c,{children:[typeof e=="function"?e({defaultChildren:void 0,...n}):e,(n.isFocusVisible||n.isSelected)&&d(m.span,{className:i("absolute z-0",o==="solid"&&"inset-0 rounded-lg bg-slate-600 mix-blend-color",o==="outline"&&"inset-0 rounded-lg border-solid border-2 border-surface-inverse-hover",o==="underline"&&"rounded-lg bg-surface-inverse-hover mix-blend-color bottom-0",o==="underline"&&s==="horizontal"&&"left-0 w-full h-px",o==="underline"&&s==="vertical"&&"right-0 w-px h-full",o==="enclosed"&&"inset-0 border-solid border-1 border-surface-inverse-hover -mb-px border-b-0 rounded-t-lg rounded-b-none bg-white mix-blend-difference",o==="base"&&"hidden",t?.overflow),layoutId:o,transition:{type:"spring",bounce:.2,duration:.75}})]})})}export{x as BaseTab,w as Tab,w as default};
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { TooltipProps } from './Tooltip.types';
|
|
2
|
+
/**
|
|
3
|
+
* Native tooltip on react-aria-components (CTAP-1383) — previously a styled
|
|
4
|
+
* wrapper around @heroui/tooltip, which pulled the @heroui system into any
|
|
5
|
+
* chunk that used it. RAC is already this library's base. Same call-site API:
|
|
6
|
+
* `<Tooltip content={...} offset={12}>{trigger}</Tooltip>` with an arbitrary
|
|
7
|
+
* trigger node (Focusable makes non-interactive children hoverable/focusable).
|
|
8
|
+
*/
|
|
9
|
+
export declare function Tooltip({ children, content, placement, offset, showArrow, isDisabled, delay, classNames, }: TooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
2
10
|
export default Tooltip;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsxs as l,jsx as e}from"react/jsx-runtime";import{TooltipTrigger as d,Focusable as f,Tooltip as m,OverlayArrow as b}from"react-aria-components";import{cn as t}from"../../utils/cn.js";function v({children:i,content:n,placement:s="top",offset:r=8,showArrow:a=!1,isDisabled:u,delay:c=500,classNames:o}){return l(d,{delay:c,isDisabled:u,children:[e(f,{children:e("span",{role:"button",tabIndex:0,className:"inline-flex outline-none",children:i})}),l(m,{placement:s,offset:r,className:t("z-50 outline-none","focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-500",o?.base),children:[a&&e(b,{children:e("span",{className:"block rotate-45 w-2.5 h-2.5 -translate-y-1/2 rounded-sm bg-slate-500 shadow-sm"})}),e("div",{className:t("inline-flex flex-col items-center justify-center outline-none","w-full py-1 px-2.5 box-border bg-slate-500 rounded-md shadow-sm","text-sm text-white subpixel-antialiased",o?.content),children:n})]})]})}export{v as Tooltip,v as default};
|
|
@@ -1,2 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Structural props (CTAP-1383) — previously re-exported from @heroui/tooltip.
|
|
4
|
+
* Covers the surface this repo uses; heroui prop names kept.
|
|
5
|
+
*/
|
|
6
|
+
export type TooltipProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
/** Tooltip body. */
|
|
9
|
+
content?: ReactNode;
|
|
10
|
+
placement?: 'top' | 'bottom' | 'left' | 'right' | 'top start' | 'top end' | 'bottom start' | 'bottom end';
|
|
11
|
+
/** Distance from the trigger, px. */
|
|
12
|
+
offset?: number;
|
|
13
|
+
showArrow?: boolean;
|
|
14
|
+
isDisabled?: boolean;
|
|
15
|
+
/** ms before showing (heroui: delay). */
|
|
16
|
+
delay?: number;
|
|
17
|
+
classNames?: {
|
|
18
|
+
base?: string;
|
|
19
|
+
content?: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Tooltip as
|
|
1
|
+
import{Tooltip as m}from"./Tooltip.js";import"react/jsx-runtime";import"react-aria-components";import"../../utils/cn.js";export{m as Tooltip};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsxs as l,Fragment as u,jsx as e}from"react/jsx-runtime";import{forwardRef as y,useState as v}from"react";import{
|
|
1
|
+
"use client";import{jsxs as l,Fragment as u,jsx as e}from"react/jsx-runtime";import{forwardRef as y,useState as v}from"react";import{m as j}from"framer-motion";import{FieldError as V}from"react-aria-components";import{cn as r}from"../../utils/cn.js";import _ from"../../hooks/useIsClient.js";import{Skeleton as p}from"../Skeleton/Skeleton.js";function k({hasTitle:a,className:s}){return l("div",{className:"w-full h-full flex flex-col gap-4",children:[a&&e(p,{className:"w-1/2 h-8 mx-auto rounded-md z-20"}),e(p,{className:r("w-full h-56 rounded-md z-20 relative",s)})]})}const H=y(({title:a,description:s="Preview will display here.",fileExtension:m,actionTitle:g="select file",variant:i,errorMessage:h,defaultImagePath:n,classNames:f,...c},b)=>{const x=_(),[t,w]=v({src:null,alt:null}),C=!!h,N=m?m.split(",").map(o=>`image/${o.trim()}`).join(", "):"image/*";return l("div",{className:r("w-full h-full","flex flex-col gap-4"),children:[x?l(u,{children:[a&&e("h6",{className:r("text-center","text-2xl","m-0 mb-4"),children:a}),l("div",{className:r("w-full h-full","flex flex-col justify-between gap-5 items-center",["bg-surface-subtle",i==="base"&&"bg-transparent"],"rounded-md",[i==="base"&&"rounded-none"],["p-6 lg:p-7",i==="base"&&"p-0 lg:p-0"]),children:[l("label",{htmlFor:`${c?.name}-upload-file`,"aria-label":"image upload",onChange:o=>{const{target:{files:d}}=o;d&&w({src:URL.createObjectURL(d[0]),alt:d[0].name})},className:r("inline-flex justify-center items-center","uppercase text-base border-border-subtle","bg-transparent","border-1 border-solid","px-4 py-0","rounded-2xl","cursor-pointer","w-full h-9",["max-w-48",i==="base"&&"max-w-none"],"my-0 mx-auto","has-[:disabled]:bg-transparent has-[:disabled]:text-fg-strong","hover:bg-slate-100s hover:text-black",f?.label),children:[g,e("input",{id:`${c?.name}-upload-file`,accept:N,type:"file",hidden:!0,...c,ref:b,className:"hidden"})]}),n&&!t.src?e("div",{className:"flex justify-center items-center w-60",children:e("a",{href:n,target:"_blank",rel:"noreferrer",children:e("img",{src:n,alt:"",className:"w-full h-auto"})})}):l(u,{children:[e(j.div,{initial:{opacity:0},animate:{opacity:1},transition:{type:"spring",duration:3,bounce:0},className:"flex justify-center items-center w-52 h-auto",children:t.src?e("img",{src:t.src,height:96,width:200,alt:t.alt||"",className:"max-h-full object-contain"}):l("svg",{xmlns:"http://www.w3.org/2000/svg",width:"31",height:"55",viewBox:"0 0 31 55",fill:"none",children:[e("g",{clipPath:"url(#clip0_15607_32844)",children:e("path",{d:"M15.9521 0.721924C24.2431 0.721924 30.9521 7.36392 30.9521 15.5719V43.9219C30.9521 49.8889 26.0703 54.7219 20.0431 54.7219C14.0158 54.7219 9.13397 49.8889 9.13397 43.9219V20.9719C9.13397 17.2459 12.1885 14.2219 15.9521 14.2219C19.7158 14.2219 22.7703 17.2459 22.7703 20.9719V41.2219H17.3158V20.7289C17.3158 19.2439 14.5885 19.2439 14.5885 20.7289V43.9219C14.5885 46.8919 17.0431 49.3219 20.0431 49.3219C23.0431 49.3219 25.4976 46.8919 25.4976 43.9219V15.5719C25.4976 10.3609 21.2158 6.12192 15.9521 6.12192C10.6885 6.12192 6.40669 10.3609 6.40669 15.5719V41.2219H0.952148V15.5719C0.952148 7.36392 7.66124 0.721924 15.9521 0.721924Z",fill:"#646464"})}),e("defs",{children:e("clipPath",{id:"clip0_15607_32844",children:e("rect",{width:"30",height:"54",fill:"white",transform:"translate(0.952148 0.721924)"})})})]})},t.src),e("p",{className:"m-0 text-fg-strong text-center",children:t.alt||s})]})]})]}):e(k,{hasTitle:!!a,className:f?.skeleton}),C&&e(V,{className:r("-mt-2","self-start"),children:h})]})});export{H as UploadImage,H as default};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# GraphQL Client Executes String Documents — graphql-request Removed
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** `utils/createAuthAwareGraphqlClient` (public API)
|
|
6
|
+
**Classification:** COMPATIBILITY (breaking)
|
|
7
|
+
**Breaking:** Yes. AST `TypedDocumentNode` documents are no longer accepted; the `GraphQLClient` re-export is gone; `ClientError` is now this module's own class.
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
The auth-aware client wrapped `graphql-request`, whose static imports put the whole
|
|
13
|
+
`graphql` package (parser, lexer, printer, AST machinery) plus `cross-fetch` into every
|
|
14
|
+
consumer page's initial JS — ~30 KB gz that existed only to turn an AST back into the
|
|
15
|
+
query text codegen started from.
|
|
16
|
+
|
|
17
|
+
## Changes
|
|
18
|
+
|
|
19
|
+
- `createAuthAwareGraphqlClient()` executes documents as **text**: one JSON POST via
|
|
20
|
+
`fetch`. Same call signatures (`request(url, document, variables?, requestHeaders?)`
|
|
21
|
+
and `.withOptions({ …, signal })`), same partial-response semantics (HTTP 200 with
|
|
22
|
+
`data` + `errors` returns the partial data), same 401/403/5xx events on
|
|
23
|
+
`authAwareEvents`, same dev field-error logging.
|
|
24
|
+
- **Documents must be strings** — codegen `TypedDocumentString`
|
|
25
|
+
(`documentMode: 'string'`) or plain strings. The new `GraphqlDocument<TData,
|
|
26
|
+
TVariables>` type carries result/variable typing structurally, so response-type
|
|
27
|
+
inference at call sites is unchanged.
|
|
28
|
+
- **`ClientError` is now defined here**, shape-compatible with `graphql-request`'s
|
|
29
|
+
(`response.status/data/errors`, `request.query/variables`). `instanceof ClientError`
|
|
30
|
+
against this module's export now always matches — the dual-package hazard the old
|
|
31
|
+
re-export warned about is gone. The identity-agnostic `getRequestErrorStatus` from
|
|
32
|
+
`utils/error` continues to work untouched.
|
|
33
|
+
- **Removed:** the `GraphQLClient` re-export (nothing to re-export), and the
|
|
34
|
+
`graphql-request` dependency (dev + peer).
|
|
35
|
+
|
|
36
|
+
## Migration
|
|
37
|
+
|
|
38
|
+
1. Switch codegen to string documents: `presetConfig`/`config` → `documentMode:
|
|
39
|
+
'string'` (client-preset ≥ 4 for `TypedDocumentString`), regenerate.
|
|
40
|
+
2. Replace `TypedDocumentNode`/`RequestDocument` types at wrapper boundaries with
|
|
41
|
+
`GraphqlDocument` / `GraphqlVariables` from this module; `GraphQLClientRequestHeaders`
|
|
42
|
+
with the platform `HeadersInit`.
|
|
43
|
+
3. Sites that imported `ClientError` from `graphql-request` import it from here.
|
|
44
|
+
4. A call that must send `FormData` or custom cors/credentials keeps using
|
|
45
|
+
`createAuthAwareFetch()` (unchanged) and `String(document)` for the query text.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# `graphql` Peer Is Covered — No More Double Bundle
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** consumers' bundle size (~12 KB gz of duplicated `graphql`)
|
|
6
|
+
**Classification:** BUGFIX (dependency resolution)
|
|
7
|
+
**Breaking:** No. `graphql ^16.6.0` is an optional peer, matching `@clicktap/state`.
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
The lib declared `graphql-request` (dev + optional peer) but not `graphql` itself.
|
|
13
|
+
With `auto-install-peers`, pnpm resolved `graphql-request`'s `graphql ^16` peer to the
|
|
14
|
+
**newest** matching version (16.14.0) while the app and `@clicktap/state` pinned 16.12.0.
|
|
15
|
+
Two full copies of the `graphql` package — parser, lexer, printer — shipped in every
|
|
16
|
+
page's initial JS. (The uncovered-peer-is-a-floating-install trap.)
|
|
17
|
+
|
|
18
|
+
## Changes
|
|
19
|
+
|
|
20
|
+
`graphql` is now declared: `16.12.0` in devDependencies, `^16.6.0` as an optional peer
|
|
21
|
+
(mirroring `@clicktap/state`). The whole runtime graph resolves a single `graphql@16.12.0`.
|
|
22
|
+
|
|
23
|
+
## What to check
|
|
24
|
+
|
|
25
|
+
After `pnpm install`, `ls node_modules/.pnpm | grep '^graphql@'` in a consuming app
|
|
26
|
+
should show one runtime version reachable from the frontend graph.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# The @heroui Dependency Is Gone — Accordion, Tooltip, Pagination, Badge Are Native
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Ticket:** CTAP-1383 (epic CTAP-1380)
|
|
6
|
+
**Affects:** Accordion, Tooltip, Pagination, Badge. Peer/dev dependencies on `@heroui/*` removed.
|
|
7
|
+
**Classification:** COMPATIBILITY
|
|
8
|
+
**Breaking:** API-compatible for every usage shape in the reference repo (inventoried below). Consumers importing `@heroui`/`@nextui-org` types directly must switch to this package's exports.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Four components wrapped `@heroui/*` while supplying ALL of their own visual
|
|
13
|
+
styling — the wrapper bought two DOM elements and a positioning engine, and
|
|
14
|
+
cost the whole @heroui system + theme (~25 KiB gz) in the initial JS of every
|
|
15
|
+
page, anchored by the PLP filter sidebar's Accordion. This library's actual
|
|
16
|
+
base is react-aria-components; the rewrites cost nothing new:
|
|
17
|
+
|
|
18
|
+
- **Accordion** → RAC `DisclosureGroup`/`Disclosure`. Height animates with
|
|
19
|
+
the CSS grid-rows trick (no animation runtime).
|
|
20
|
+
- **Tooltip** → RAC `TooltipTrigger`/`Tooltip`/`OverlayArrow` (`Focusable`
|
|
21
|
+
makes arbitrary trigger nodes hoverable).
|
|
22
|
+
- **Pagination** → native boundary/sibling windowing.
|
|
23
|
+
- **Badge** → the two wrapper elements, inline.
|
|
24
|
+
|
|
25
|
+
## Preserved API surface (inventoried from real call sites)
|
|
26
|
+
|
|
27
|
+
- Accordion: `selectionMode`, `defaultSelectedKeys` (incl. `"all"`),
|
|
28
|
+
`defaultExpandedKeys`, controlled `selectedKeys` + `onSelectionChange`,
|
|
29
|
+
`disallowEmptySelection`, `hideIndicator` (group and per-item),
|
|
30
|
+
`showDivider`/`dividerProps` (an `<hr>` between items — `[&_hr]:hidden`
|
|
31
|
+
keeps working), `itemClasses`/per-item `classNames` slots, per-item
|
|
32
|
+
`title`/`subtitle`/`startContent`/`indicator` (a component still receives
|
|
33
|
+
`{ isOpen }` — import `AccordionItemIndicatorProps` from HERE now),
|
|
34
|
+
`disableIndicatorAnimation`, `onPress`, and the `data-open` attribute on
|
|
35
|
+
heading/trigger/indicator that `data-[open=true]:` selectors style.
|
|
36
|
+
- Tooltip: `content`, `offset`, `placement`, `showArrow`, `delay`,
|
|
37
|
+
`isDisabled`, `classNames.base/content`, arbitrary child as trigger.
|
|
38
|
+
- Pagination: `total`, `page`/`initialPage`, `onChange`, `boundaries`,
|
|
39
|
+
`siblings`, `showControls`, `isCompact`, `classNames` slots incl.
|
|
40
|
+
`data-[active=true]`/`data-[disabled=true]` styling hooks.
|
|
41
|
+
- Badge: unchanged names (`content`, `isInvisible`, `placement`, `shape`,
|
|
42
|
+
`size`, `variant`, `showOutline`, `isDot`, `classNames`).
|
|
43
|
+
|
|
44
|
+
## What you need to do
|
|
45
|
+
|
|
46
|
+
- Remove `@heroui/*` and `@nextui-org/*` from your app's dependencies if they
|
|
47
|
+
existed only for these components or their types; import the types from
|
|
48
|
+
this package instead (`AccordionItemIndicatorProps` moved here).
|
|
49
|
+
- If you used heroui props OUTSIDE the surface above, check the component
|
|
50
|
+
source — the compat layer is deliberate, not exhaustive.
|
|
51
|
+
- Verified on the reference storefront: PLP filter accordion (expand/
|
|
52
|
+
collapse/apply, all-open default, indicator rotation), checkout accordions
|
|
53
|
+
(controlled single-selection payment list, promo/gift-card items), cart
|
|
54
|
+
badge, dividers, `data-open` styling. ~54 KiB gz off the initial bundle.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Animated Components Render `m.*` — Apps Must Provide LazyMotion Features
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Ticket:** CTAP-1383 (epic CTAP-1380)
|
|
6
|
+
**Affects:** every animated component (ModalOverlay, Drawer, Dialog, Menu, ContextMenu, Tabs, Badge, Collapsible, NumberTicker, Meter, Progressbar, UploadImage).
|
|
7
|
+
**Classification:** COMPATIBILITY
|
|
8
|
+
**Breaking:** Animations no-op (components still render and function) until the consuming app mounts a `LazyMotion` provider.
|
|
9
|
+
|
|
10
|
+
## What changed
|
|
11
|
+
|
|
12
|
+
Every framer-motion element in this library is now `m.*` instead of
|
|
13
|
+
`motion.*`. Under framer's LazyMotion pattern, `m` components carry no
|
|
14
|
+
animation runtime of their own — the feature set loads from a provider the
|
|
15
|
+
APP mounts, as an async chunk.
|
|
16
|
+
|
|
17
|
+
Why: `motion.*` imports statically bundle the full framer runtime (~38 KiB
|
|
18
|
+
gz). Because overlay primitives (ModalOverlay, Drawer, Badge) sit in every
|
|
19
|
+
storefront's layout, that runtime shipped in the initial JS of every page.
|
|
20
|
+
With `m.*`, the initial bundle carries only framer's slim core and the
|
|
21
|
+
features arrive async — measured ~0.2-0.5s of simulated-mobile LCP on the
|
|
22
|
+
reference storefront.
|
|
23
|
+
|
|
24
|
+
## What you need to do
|
|
25
|
+
|
|
26
|
+
Mount a `LazyMotion` provider above everything that renders these components
|
|
27
|
+
(both root layouts in the reference app):
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
'use client';
|
|
31
|
+
import { LazyMotion } from 'framer-motion';
|
|
32
|
+
|
|
33
|
+
const loadFeatures = () => import('./motionFeatures').then((m) => m.default);
|
|
34
|
+
// motionFeatures.ts: import { domMax } from 'framer-motion'; export default domMax;
|
|
35
|
+
|
|
36
|
+
export function MotionProvider({ children }) {
|
|
37
|
+
return <LazyMotion features={loadFeatures}>{children}</LazyMotion>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Two load-bearing details:
|
|
42
|
+
|
|
43
|
+
- the features import lives in its OWN file — inlining `domMax` into the
|
|
44
|
+
provider keeps it in the provider's (initial) chunk, defeating the point;
|
|
45
|
+
- use `domMax` if anything in your tree uses layout animations
|
|
46
|
+
(`layout`/`layoutId` props); `domAnimation` otherwise.
|
|
47
|
+
|
|
48
|
+
Without a provider nothing errors: components mount, function, and simply
|
|
49
|
+
appear without transitions. If your drawers/dialogs "stopped animating"
|
|
50
|
+
after this release, the missing provider is why.
|
|
51
|
+
|
|
52
|
+
Do not use `strict` on the provider if any code in the tree still renders
|
|
53
|
+
full `motion.*` — full-motion elements are self-contained and coexist fine
|
|
54
|
+
without strict.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Modal Triggers Are Wired Explicitly; Overlay Animation Back on `motion`
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** DialogTrigger, ModalOverlay, Dialog
|
|
6
|
+
**Classification:** BUGFIX
|
|
7
|
+
**Breaking:** No. Same component APIs; consumer `onPress` on the trigger child still runs (chained).
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
## Problems
|
|
11
|
+
|
|
12
|
+
1. **Trigger-driven modals never opened** — every uncontrolled `DialogTrigger` modal
|
|
13
|
+
(account address/payment create-edit-delete, delete confirmations) rendered an inert
|
|
14
|
+
button: react-aria-components wires its trigger through `PressResponderContext`, and in
|
|
15
|
+
this app's production bundles that registration silently never reaches the Button (no
|
|
16
|
+
aria attributes applied, press never toggles state) — with a verified-single instance
|
|
17
|
+
of react-aria-components, @react-aria/interactions, react, and framer-motion in the
|
|
18
|
+
bundle, so it is NOT the dual-package hazard CTAP-1210 fixed. Every working modal in
|
|
19
|
+
the app (FilterButton, RegionSelectAction, CartDrawer) works because it passes an
|
|
20
|
+
explicit `onPress`/controlled `isOpen`. Evidence says this has been broken on master
|
|
21
|
+
too (the same missing aria attributes on QA's trigger buttons).
|
|
22
|
+
2. **`m.create` broke controlled modals** — the CTAP-1383 LazyMotion conversion switched
|
|
23
|
+
`motion.create(...)` to `m.create(...)` in ModalOverlay/Dialog. In production browser
|
|
24
|
+
bundles the m-created overlay never mounts its portal (works in jsdom; browser-only).
|
|
25
|
+
Verified by A/B builds: identical code with `motion.create` opens, `m.create` does not.
|
|
26
|
+
|
|
27
|
+
## Changes
|
|
28
|
+
|
|
29
|
+
- `DialogTrigger` no longer wraps react-aria-components' DialogTrigger. It owns a
|
|
30
|
+
`useOverlayTriggerState`, provides it on `OverlayTriggerStateContext` (which both our
|
|
31
|
+
ModalOverlay and react-aria's read), and clones the first child with an explicit
|
|
32
|
+
`onPress` that toggles the state — the mechanism the rest of the app already proves
|
|
33
|
+
out. A consumer-supplied `onPress` is chained before the toggle. The `useDialogTrigger`
|
|
34
|
+
shim is unchanged.
|
|
35
|
+
- `ModalOverlay`/`Dialog` are back on `motion.create` (costs ~18 KB gz of initial JS vs
|
|
36
|
+
the m form — the price of modals that open). Root-causing why `m.create` + react-aria
|
|
37
|
+
overlays fail in production bundles is a follow-up; if solved, the m form can return.
|
|
38
|
+
|
|
39
|
+
## What to check
|
|
40
|
+
|
|
41
|
+
Any `DialogTrigger` + `Button` + `ModalOverlay` combination opens on press — uncontrolled
|
|
42
|
+
(account pages) and controlled (PLP filter) alike. Dialog `aria-label`s are now the only
|
|
43
|
+
labelling source (the react-aria trigger-id fallback is gone) — our dialogs all pass one.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# next Image: the optimizer-failure fallback keeps fill semantics
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-21
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Ticket:** CTAP-1376 (found during the CTAP-1375 QA incident)
|
|
6
|
+
**Affects:** `@clicktap/ui/next/Image` — every `fill`-mode usage. No consumer code change.
|
|
7
|
+
**Classification:** BUGFIX
|
|
8
|
+
**Breaking:** No
|
|
9
|
+
|
|
10
|
+
## The failure this removes
|
|
11
|
+
|
|
12
|
+
When `next/image` optimization fails, this wrapper bypasses it and renders the
|
|
13
|
+
raw src as a plain `<img>` (the `onError` debounce path and the render-error
|
|
14
|
+
boundary). Both forwarded `className`, `style` and `width`/`height` — but a
|
|
15
|
+
`fill` image has no width/height props, and its positioning
|
|
16
|
+
(`position:absolute; inset:0; height/width:100%`) is inline style **NextImage
|
|
17
|
+
itself adds**, which the fallback bypassed along with the optimizer.
|
|
18
|
+
|
|
19
|
+
So a fill image whose optimizer fetch failed degraded catastrophically instead
|
|
20
|
+
of gracefully: before the raw src loaded it sat as a broken icon at its
|
|
21
|
+
container's top-left; once loaded it rendered at NATURAL size — a 2880px
|
|
22
|
+
category hero escaping its `relative overflow-hidden` banner and filling
|
|
23
|
+
multiple viewports. With an environment-wide optimizer failure (CTAP-1375:
|
|
24
|
+
media URLs pointing at an unreachable host) that was every banner on the site.
|
|
25
|
+
|
|
26
|
+
## The fix
|
|
27
|
+
|
|
28
|
+
When the props include `fill`, both fallback `<img>`s re-apply the same inline
|
|
29
|
+
styles NextImage would have (`position:absolute; height/width:100%;
|
|
30
|
+
left/top/right/bottom:0`), merged under the caller's `style`. `object-fit`
|
|
31
|
+
still arrives via the forwarded `className` (`object-cover` etc.). Sized
|
|
32
|
+
images (width/height props) are byte-for-byte unchanged.
|
|
33
|
+
|
|
34
|
+
## What you need to do
|
|
35
|
+
|
|
36
|
+
Nothing — take the release. If you have ever worked around this with wrapper
|
|
37
|
+
divs or manual absolute positioning around a fill-mode `Image` specifically
|
|
38
|
+
for its error state, that can come off.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Accordion Divider Renders BETWEEN Items; react-aria Stack Aligned
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-22
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** Accordion consumers using `dividerProps` as an inter-item spacer (checkout payment methods); every react-aria-components consumer
|
|
6
|
+
**Classification:** BUGFIX
|
|
7
|
+
**Breaking:** No (peer ranges raised: react-aria ^3.48, react-aria-components ^1.17, react-stately ^3.46).
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
## Problems
|
|
11
|
+
|
|
12
|
+
1. **Divider inside the item box.** The CTAP-1383 Accordion rewrite rendered the
|
|
13
|
+
between-items `<hr>` INSIDE each Disclosure — inside the consumer's bordered
|
|
14
|
+
`itemClasses.base` box. The checkout payment list styles the divider as an invisible
|
|
15
|
+
`h-4` spacer meant as a GAP between boxes, so every payment method carried ~32px of
|
|
16
|
+
dead space under its title. heroui rendered dividers between items; the rewrite now
|
|
17
|
+
does too (a sibling after each Disclosure).
|
|
18
|
+
2. **Mixed react-aria internals.** The repo pinned react-aria 3.46 / react-aria-components
|
|
19
|
+
1.15 while pnpm resolved newer @react-aria internals into their closures. Production
|
|
20
|
+
bundles with that mix showed a family of RAC-internal failures jsdom never caught:
|
|
21
|
+
Table rows losing their cells on hover (account orders emptying), and the
|
|
22
|
+
PressResponder trigger wiring never reaching Buttons. Dev/peer versions now align on
|
|
23
|
+
the coherent set: react-aria 3.48.0, react-aria-components 1.17.0, react-stately
|
|
24
|
+
3.46.0 — verified to fix the Table hover failure outright.
|
|
25
|
+
|
|
26
|
+
## What to check
|
|
27
|
+
|
|
28
|
+
Payment methods render as compact bordered rows (divider = gap, not in-box padding).
|
|
29
|
+
Account orders survive hovering/navigating rows. Bordered/splitted Accordion variants
|
|
30
|
+
keep their internal spacing (those style the divider as a visible rule, unaffected).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Accordion `dividerProps.className` Owns the Divider Outright
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-22
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** Accordion consumers styling the inter-item divider
|
|
6
|
+
**Classification:** BUGFIX
|
|
7
|
+
**Breaking:** No.
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
A consumer-supplied `dividerProps.className` now replaces the default divider classes
|
|
11
|
+
(spacing and color) instead of stacking on top of them. The checkout payment list
|
|
12
|
+
styles the divider as an invisible `h-4` spacer; with the default `my-2` still applied
|
|
13
|
+
the gap between items doubled to 32px. Consumers that pass no className keep the
|
|
14
|
+
default `my-2` rule.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# react-aria Moves as One Version Set
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-22
|
|
4
|
+
**Package:** `@clicktap/ui`
|
|
5
|
+
**Affects:** every consumer of react-aria-components — dependency policy, not an API change
|
|
6
|
+
**Classification:** COMPATIBILITY
|
|
7
|
+
**Read before updating:** never bump `react-aria`, `react-aria-components`, or `react-stately` independently — skewed internals fail silently, and only in production bundles.
|
|
8
|
+
**Ticket:** CTAP-1383
|
|
9
|
+
|
|
10
|
+
## The finding
|
|
11
|
+
|
|
12
|
+
The repo pinned `react-aria-components@1.15.1` / `react-aria@3.46.0` while pnpm resolved
|
|
13
|
+
NEWER `@react-aria/*` subpackages into their closures (an ordinary lockfile drift — the
|
|
14
|
+
packages install fine, typecheck fine, and every jest suite passes). The mixed internals
|
|
15
|
+
produced a family of failures that exist **only in production browser bundles**:
|
|
16
|
+
|
|
17
|
+
- **Uncontrolled `DialogTrigger` modals were dead.** The PressResponder trigger wiring
|
|
18
|
+
never reached the Button: the trigger props arrived structurally but valueless, presses
|
|
19
|
+
never toggled the overlay state. Every account modal (address/payment create, edit,
|
|
20
|
+
delete confirmations) silently did nothing — on master too.
|
|
21
|
+
- **`Table` rows lost their cells on hover.** Sweeping the pointer across the account
|
|
22
|
+
orders table emptied every `<tr>` (row elements remain, children gone) — the "my orders
|
|
23
|
+
disappear when I hover them" report. Click-through and back-navigation compounded it.
|
|
24
|
+
- Likely related, unproven: `m.create()`-wrapped RAC overlays never mounting their portal
|
|
25
|
+
(see the modal-triggers guide) — same only-in-production signature.
|
|
26
|
+
|
|
27
|
+
None of this reproduces in jsdom. All package instances were verified single-copy in the
|
|
28
|
+
bundle (this is NOT the CTAP-1210 dual-package hazard), which is what makes the skew so
|
|
29
|
+
hard to see: the failure lives in version-mismatched internals of one coherent-looking
|
|
30
|
+
install.
|
|
31
|
+
|
|
32
|
+
## The rule
|
|
33
|
+
|
|
34
|
+
`react-aria`, `react-aria-components`, and `react-stately` are released together and must
|
|
35
|
+
be adopted together. This package's devDependencies pin one coherent set (currently
|
|
36
|
+
3.48.0 / 1.17.0 / 3.46.0) and its peer ranges floor consumers at the same set; the
|
|
37
|
+
reference app pins the identical versions. When bumping, take the trio from the same
|
|
38
|
+
react-aria release announcement and re-run the production-bundle checks below —
|
|
39
|
+
aligning to the coherent set fixed the Table failure outright with no code change.
|
|
40
|
+
|
|
41
|
+
## How to verify (jsdom cannot)
|
|
42
|
+
|
|
43
|
+
Probe a production build in a real browser: open an uncontrolled DialogTrigger modal
|
|
44
|
+
(account → Add Address), hover-sweep the orders table rows and count `[role="row"]`
|
|
45
|
+
children, and diff `.pnpm` instance DIRS — key on the full directory name, not
|
|
46
|
+
`name@version`, or two peer-hash instances of the same version collapse into one.
|
|
@@ -1,4 +1,95 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"path": "2026/08/ui-2026-08-22-react-aria-moves-as-one-version-set.md",
|
|
4
|
+
"module": "libs/frontend-modules/ui",
|
|
5
|
+
"package": "@clicktap/ui",
|
|
6
|
+
"date": "2026-08-22",
|
|
7
|
+
"title": "react-aria Moves as One Version Set",
|
|
8
|
+
"classification": "COMPATIBILITY",
|
|
9
|
+
"breaking": "",
|
|
10
|
+
"affects": "every consumer of react-aria-components — dependency policy, not an API change",
|
|
11
|
+
"read_before_updating": "never bump `react-aria`, `react-aria-components`, or `react-stately` independently — skewed internals fail silently, and only in production bundles."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"path": "2026/08/ui-2026-08-22-accordion-divider-class-ownership.md",
|
|
15
|
+
"module": "libs/frontend-modules/ui",
|
|
16
|
+
"package": "@clicktap/ui",
|
|
17
|
+
"date": "2026-08-22",
|
|
18
|
+
"title": "Accordion `dividerProps.className` Owns the Divider Outright",
|
|
19
|
+
"classification": "BUGFIX",
|
|
20
|
+
"breaking": "No.",
|
|
21
|
+
"affects": "Accordion consumers styling the inter-item divider"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "2026/08/ui-2026-08-22-accordion-divider-between-items.md",
|
|
25
|
+
"module": "libs/frontend-modules/ui",
|
|
26
|
+
"package": "@clicktap/ui",
|
|
27
|
+
"date": "2026-08-22",
|
|
28
|
+
"title": "Accordion Divider Renders BETWEEN Items; react-aria Stack Aligned",
|
|
29
|
+
"classification": "BUGFIX",
|
|
30
|
+
"breaking": "No (peer ranges raised: react-aria ^3.48, react-aria-components ^1.17, react-stately ^3.46).",
|
|
31
|
+
"affects": "Accordion consumers using `dividerProps` as an inter-item spacer (checkout payment methods); every react-aria-components consumer"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"path": "2026/08/ui-2026-08-21-next-image-fallback-keeps-fill.md",
|
|
35
|
+
"module": "libs/frontend-modules/ui",
|
|
36
|
+
"package": "@clicktap/ui",
|
|
37
|
+
"date": "2026-08-21",
|
|
38
|
+
"title": "next Image: the optimizer-failure fallback keeps fill semantics",
|
|
39
|
+
"classification": "BUGFIX",
|
|
40
|
+
"breaking": "No",
|
|
41
|
+
"affects": "`@clicktap/ui/next/Image` — every `fill`-mode usage. No consumer code change."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "2026/08/ui-2026-08-21-modal-triggers-wired-explicitly.md",
|
|
45
|
+
"module": "libs/frontend-modules/ui",
|
|
46
|
+
"package": "@clicktap/ui",
|
|
47
|
+
"date": "2026-08-21",
|
|
48
|
+
"title": "Modal Triggers Are Wired Explicitly; Overlay Animation Back on `motion`",
|
|
49
|
+
"classification": "BUGFIX",
|
|
50
|
+
"breaking": "No. Same component APIs; consumer `onPress` on the trigger child still runs (chained).",
|
|
51
|
+
"affects": "DialogTrigger, ModalOverlay, Dialog"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"path": "2026/08/ui-2026-08-21-lazymotion-m-components.md",
|
|
55
|
+
"module": "libs/frontend-modules/ui",
|
|
56
|
+
"package": "@clicktap/ui",
|
|
57
|
+
"date": "2026-08-21",
|
|
58
|
+
"title": "Animated Components Render `m.*` — Apps Must Provide LazyMotion Features",
|
|
59
|
+
"classification": "COMPATIBILITY",
|
|
60
|
+
"breaking": "Animations no-op (components still render and function) until the consuming app mounts a `LazyMotion` provider.",
|
|
61
|
+
"affects": "every animated component (ModalOverlay, Drawer, Dialog, Menu, ContextMenu, Tabs, Badge, Collapsible, NumberTicker, Meter, Progressbar, UploadImage)."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"path": "2026/08/ui-2026-08-21-heroui-removed.md",
|
|
65
|
+
"module": "libs/frontend-modules/ui",
|
|
66
|
+
"package": "@clicktap/ui",
|
|
67
|
+
"date": "2026-08-21",
|
|
68
|
+
"title": "The @heroui Dependency Is Gone — Accordion, Tooltip, Pagination, Badge Are Native",
|
|
69
|
+
"classification": "COMPATIBILITY",
|
|
70
|
+
"breaking": "API-compatible for every usage shape in the reference repo (inventoried below). Consumers importing `@heroui`/`@nextui-org` types directly must switch to this package's exports.",
|
|
71
|
+
"affects": "Accordion, Tooltip, Pagination, Badge. Peer/dev dependencies on `@heroui/*` removed."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"path": "2026/08/ui-2026-08-21-graphql-peer-covered.md",
|
|
75
|
+
"module": "libs/frontend-modules/ui",
|
|
76
|
+
"package": "@clicktap/ui",
|
|
77
|
+
"date": "2026-08-21",
|
|
78
|
+
"title": "`graphql` Peer Is Covered — No More Double Bundle",
|
|
79
|
+
"classification": "BUGFIX (dependency resolution)",
|
|
80
|
+
"breaking": "No. `graphql ^16.6.0` is an optional peer, matching `@clicktap/state`.",
|
|
81
|
+
"affects": "consumers' bundle size (~12 KB gz of duplicated `graphql`)"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"path": "2026/08/ui-2026-08-21-graphql-client-string-documents.md",
|
|
85
|
+
"module": "libs/frontend-modules/ui",
|
|
86
|
+
"package": "@clicktap/ui",
|
|
87
|
+
"date": "2026-08-21",
|
|
88
|
+
"title": "GraphQL Client Executes String Documents — graphql-request Removed",
|
|
89
|
+
"classification": "COMPATIBILITY (breaking)",
|
|
90
|
+
"breaking": "Yes. AST `TypedDocumentNode` documents are no longer accepted; the `GraphQLClient` re-export is gone; `ClientError` is now this module's own class.",
|
|
91
|
+
"affects": "`utils/createAuthAwareGraphqlClient` (public API)"
|
|
92
|
+
},
|
|
2
93
|
{
|
|
3
94
|
"path": "2026/08/ui-2026-08-14-zod-error-map.md",
|
|
4
95
|
"module": "libs/frontend-modules/ui",
|
package/next/Image.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as r}from"react/jsx-runtime";import F from"next/image";import{useState as R,useRef as T,Component as b}from"react";import{cn as x}from"../utils/cn.js";import{useManagedOpacity as z,useImageStyle as B,getSrcKey as u,resolveSrc as g}from"../components/Image/imageShared.js";const m=new Set,K={position:"absolute",height:"100%",width:"100%",left:0,top:0,right:0,bottom:0};class A extends b{constructor(){super(...arguments),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}render(){if(this.state.hasError){m.add(u(this.props.src));const{src:e,alt:n,className:a,style:l,width:s,height:o}=this.props;return r("img",{src:g(e),alt:n??"",className:a,style:l,width:s,height:o,loading:"lazy"})}return this.props.children}}function N({src:i,className:e,style:n,dimmed:a,hidden:l,onReady:s,onLoad:o,...t}){const[f,p]=R(null),c=T(),{managed:y,setLoadingImg:S,onReadyRef:w,opacityStyle:E}=z({src:i,dimmed:a,hidden:l,onReady:s}),L="width"in t&&"height"in t&&!("fill"in t),h=B(n,L),d="fill"in t&&!!t.fill?{...K,...h}:h,v=u(i);return f===i||m.has(v)?r("img",{src:g(i),alt:t.alt??"",className:e,style:d,width:"width"in t?t.width:void 0,height:"height"in t?t.height:void 0,loading:"lazy"}):r(A,{src:i,alt:t.alt,className:e,style:d,width:"width"in t?t.width:void 0,height:"height"in t?t.height:void 0,children:r(F,{src:i,className:x(y&&"transition-opacity duration-200 ease-in-out",e),style:{...h,...E},onError:()=>{c.current=setTimeout(()=>p(i),2e3)},onLoad:I=>{clearTimeout(c.current),S(!1),w.current?.(),typeof o=="function"&&o(I)},...t})})}export{N as Image,N as default};
|