@plastic-js/tsumiki 0.1.14 → 0.1.16
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 +6 -0
- package/dist/components/FilterableSelectMobile.js +3 -0
- package/dist/components/FilterableSelectMobile.js.map +1 -1
- package/dist/components/SelectMobile/index.js +6 -5
- package/dist/components/SelectMobile/index.js.map +1 -1
- package/dist/components/SwipeReveal.js +34 -13
- package/dist/components/SwipeReveal.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,6 +65,12 @@ function Example(){
|
|
|
65
65
|
| `className` | `string` | — | CSS class for the trigger button |
|
|
66
66
|
| `children` | `node` | — | Custom trigger content (replaces default label + chevron) |
|
|
67
67
|
|
|
68
|
+
> **Note on Trigger element:** The trigger renders `<div role="button" tabIndex={0}>` instead of a native `<button>` as a defense-in-depth measure against a **Chrome iOS (WebKit) focus-lock bug**.
|
|
69
|
+
>
|
|
70
|
+
> The primary fix is in `SelectMobile.Content`: the sheet is rendered inline (no `<Portal>`) so it stays inside the parent Dialog's focus-trap boundary. However, the `<div role="button">` is kept as an additional safeguard — in WebKit, tapping a `<button>` inside a scrollable container with `-webkit-overflow-scrolling: touch` can pin `activeElement` to the button, causing subsequent `focus()` calls on the filter `<input>` to be silently ignored. A `<div role="button">` is semantically equivalent for accessibility but does not trigger this WebKit focus-lock behaviour.
|
|
71
|
+
>
|
|
72
|
+
> Typically a native `<button>` would be preferred for keyboard tab navigation (`tabIndex` works natively). On mobile, however, keyboard tab navigation is irrelevant — the sheet is operated via touch, and the Escape key for closing is handled by the `Dialog`-like overlay, not by tab order. The `tabIndex={0}` on the `<div>` preserves keyboard discoverability for assistive technology while working around the iOS focus trap.
|
|
73
|
+
|
|
68
74
|
**SelectMobile.Content props:**
|
|
69
75
|
|
|
70
76
|
| Prop | Type | Default | Description |
|
|
@@ -95,6 +95,9 @@ var FilterableSelectMobile = (props) => {
|
|
|
95
95
|
setProp(_el0, "value", () => query);
|
|
96
96
|
setProp(_el0, "onInput", (e) => query(e.target.value));
|
|
97
97
|
setProp(_el0, "onClick", (e) => e.stopPropagation());
|
|
98
|
+
setProp(_el0, "onPointerDown", (e) => {
|
|
99
|
+
e.target.focus({ preventScroll: true });
|
|
100
|
+
});
|
|
98
101
|
return _el0;
|
|
99
102
|
})(), () => {
|
|
100
103
|
const list = filteredItems();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterableSelectMobile.js","names":["css","createSignal","splitProps","SelectMobile","_tmpl2","_template","_tmpl","inputClass","width","height","padding","marginBottom","background","border","borderRadius","color","fontSize","fontFamily","outline","boxSizing","borderColor","noResultsClass","textAlign","defaultItemToValue","item","value","defaultItemToLabel","label","String","defaultFilter","query","itemToLabel","toLowerCase","includes","FilterableSelectMobile","props","local","itemToValue","filter","inputEl","filteredItems","q","trim","list","items","handleOpenChange","isOpen","queueMicrotask","focus","_jsx","Root","_mergeProps","onValueChange","onOpenChange","children","Trigger","placeholder","Content","clearable","clearLabel","backdropClassName","backdropStyle","_el0","cloneNode","_setProp","el","e","target","stopPropagation","length","map","Item","key"],"sources":["../../src/components/FilterableSelectMobile.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createSignal, splitProps } from '@plastic-js/plastic'\nimport { SelectMobile } from './SelectMobile/index.jsx'\n\n// ── Styles ───────────────────────────────────────────────────────────────\nconst inputClass = css({\n\twidth: '100%',\n\theight: '42px',\n\tpadding: '0 14px',\n\tmarginBottom: '6px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\toutline: 'none',\n\tboxSizing: 'border-box',\n\t'&:focus': { borderColor: 'var(--accent)' },\n\t'&::placeholder': { color: 'var(--muted)' },\n})\n\nconst noResultsClass = css({\n\tpadding: '20px 14px',\n\ttextAlign: 'center',\n\tcolor: 'var(--muted)',\n\tfontSize: '14px',\n})\n\n// ── Default accessors ────────────────────────────────────────────────────\nconst defaultItemToValue = item=> item?.value ?? item\nconst defaultItemToLabel = item=> item?.label ?? String(item)\nconst defaultFilter = (item, query, itemToLabel)=> itemToLabel(item).toLowerCase().includes(query)\n\n// ── FilterableSelectMobile ───────────────────────────────────────────────\n//\n// A mobile bottom-sheet select with a filter input at the top of the list.\n// Wraps SelectMobile internally — exposes a flat single-component API.\n//\n// Props:\n// items data array (or getter)\n// value current value (string | getter)\n// onValueChange (value) => void\n// itemToValue (item) => string — default item.value ?? item\n// itemToLabel (item) => string — default item.label ?? String(item)\n// placeholder trigger placeholder text — default \"Select\"\n// filter (item, query, itemToLabel) => boolean — default substring match\n// clearable show a \"clear\" row\n// clearLabel label for the clear row\n// backdropClassName className for the backdrop\n// backdropStyle inline style for the backdrop\nconst FilterableSelectMobile = (props)=> {\n\tconst [local] = splitProps(props, [\n\t\t'items', 'value', 'onValueChange',\n\t\t'itemToValue', 'itemToLabel',\n\t\t'placeholder', 'filter',\n\t\t'clearable', 'clearLabel',\n\t\t'backdropClassName', 'backdropStyle',\n\t])\n\n\tconst itemToValue = local.itemToValue ?? defaultItemToValue\n\tconst itemToLabel = local.itemToLabel ?? defaultItemToLabel\n\tconst filter = local.filter ?? defaultFilter\n\n\tconst query = createSignal('')\n\tlet inputEl = null\n\n\t// Reactive filter — recomputes on typing and items changes.\n\tconst filteredItems = ()=> {\n\t\tconst q = query().trim().toLowerCase()\n\t\tconst list = typeof local.items === 'function' ? local.items() : (local.items ?? [])\n\t\treturn q ? list.filter(item=> filter(item, q, itemToLabel)) : list\n\t}\n\n\t// Auto-focus the input when the sheet opens; clear query on close.\n\tconst handleOpenChange = (isOpen)=> {\n\t\tif (isOpen){\n\t\t\tqueueMicrotask(()=> inputEl?.focus())\n\t\t} else {\n\t\t\tquery('')\n\t\t}\n\t}\n\n\treturn (\n\t\t<SelectMobile.Root\n\t\t\tvalue={local.value}\n\t\t\tonValueChange={local.onValueChange}\n\t\t\titems={local.items}\n\t\t\titemToValue={itemToValue}\n\t\t\titemToLabel={itemToLabel}\n\t\t\tonOpenChange={handleOpenChange}\n\t\t>\n\t\t\t<SelectMobile.Trigger placeholder={local.placeholder} />\n\t\t\t<SelectMobile.Content\n\t\t\t\tclearable={local.clearable}\n\t\t\t\tclearLabel={local.clearLabel}\n\t\t\t\tbackdropClassName={local.backdropClassName}\n\t\t\t\tbackdropStyle={local.backdropStyle}\n\t\t\t>\n\t\t\t\t<input\n\t\t\t\t\tref={el=> { inputEl = el }}\n\t\t\t\t\ttype='text'\n\t\t\t\t\tclassName={inputClass}\n\t\t\t\t\tplaceholder='Filter…'\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tonInput={e=> query(e.target.value)}\n\t\t\t\t\tonClick={e=> e.stopPropagation()}\n\t\t\t\t/>\n\t\t\t\t{()=> {\n\t\t\t\t\tconst list = filteredItems()\n\t\t\t\t\tif (list.length === 0){\n\t\t\t\t\t\treturn <div className={noResultsClass}>No results</div>\n\t\t\t\t\t}\n\t\t\t\t\treturn list.map(item => (\n\t\t\t\t\t\t<SelectMobile.Item item={item} key={itemToValue(item)} />\n\t\t\t\t\t))\n\t\t\t\t}}\n\t\t\t</SelectMobile.Content>\n\t\t</SelectMobile.Root>\n\t)\n}\n\nexport default FilterableSelectMobile"],"mappings":";;;;;AAIA,IAAAI,SAAAC,SAAA,uBAAA;AAAA,IAAAC,QAAAD,SAAA,+CAAA;AACA,IAAME,aAAaP,IAAI;CACtBQ,OAAO;CACPC,QAAQ;CACRC,SAAS;CACTC,cAAc;CACdC,YAAY;CACZC,QAAQ;CACRC,cAAc;CACdC,OAAO;CACPC,UAAU;CACVC,YAAY;CACZC,SAAS;CACTC,WAAW;CACX,WAAW,EAAEC,aAAa,gBAAgB;CAC1C,kBAAkB,EAAEL,OAAO,eAAe;AAC3C,CAAC;AAED,IAAMM,iBAAiBrB,IAAI;CAC1BU,SAAS;CACTY,WAAW;CACXP,OAAO;CACPC,UAAU;AACX,CAAC;AAGD,IAAMO,sBAAqBC,SAAOA,MAAMC,SAASD;AACjD,IAAME,sBAAqBF,SAAOA,MAAMG,SAASC,OAAOJ,IAAI;AAC5D,IAAMK,iBAAiBL,MAAMM,OAAOC,gBAAeA,YAAYP,IAAI,EAAEQ,YAAY,EAAEC,SAASH,KAAK;AAmBjG,IAAMI,0BAA0BC,UAAS;CACxC,MAAM,CAACC,SAASlC,WAAWiC,OAAO;EACjC;EAAS;EAAS;EAClB;EAAe;EACf;EAAe;EACf;EAAa;EACb;EAAqB;CAAe,CACpC;CAED,MAAME,cAAcD,MAAMC,eAAed;CACzC,MAAMQ,cAAcK,MAAML,eAAeL;CACzC,MAAMY,SAASF,MAAME,UAAUT;CAE/B,MAAMC,QAAQ7B,aAAa,EAAE;CAC7B,IAAIsC,UAAU;CAGd,MAAMC,sBAAqB;EAC1B,MAAMC,IAAIX,MAAM,EAAEY,KAAK,EAAEV,YAAY;EACrC,MAAMW,OAAO,OAAOP,MAAMQ,UAAU,aAAaR,MAAMQ,MAAM,IAAKR,MAAMQ,SAAS,CAAA;EACjF,OAAOH,IAAIE,KAAKL,QAAOd,SAAOc,OAAOd,MAAMiB,GAAGV,WAAW,CAAC,IAAIY;CAC/D;CAGA,MAAME,oBAAoBC,WAAU;EACnC,IAAIA,QACHC,qBAAoBR,SAASS,MAAM,CAAC;OAEpClB,MAAM,EAAE;CAEV;CAEA,OAAAmB,IAAA9C,aAAA+C,MAAAC,WAAA;EAAA,IAAA1B,QAAA;GAAA,OAESW,MAAMX;EAAK;EAAA,IAAA2B,gBAAA;GAAA,OACHhB,MAAMgB;EAAa;EAAA,IAAAR,QAAA;GAAA,OAC3BR,MAAMQ;EAAK;EACLP;EACAN;EAAWsB,cACVR;EAAgBS,UAAA,CAAAL,IAAA9C,aAAAoD,SAAAJ,WAAA,EAAA,IAAAK,cAAA;GAAA,OAEKpB,MAAMoB;EAAW,EAAA,CAAA,CAAA,GAAAP,IAAA9C,aAAAsD,SAAAN,WAAA;GAAA,IAAAO,YAAA;IAAA,OAExCtB,MAAMsB;GAAS;GAAA,IAAAC,aAAA;IAAA,OACdvB,MAAMuB;GAAU;GAAA,IAAAC,oBAAA;IAAA,OACTxB,MAAMwB;GAAiB;GAAA,IAAAC,gBAAA;IAAA,OAC3BzB,MAAMyB;GAAa;GAAAP,UAAA,QAAA;IAAA,MAAAQ,OAAAxD,MAAAyD,UAAA,IAAA;IAAAC,QAAAF,MAAA,QAG5BG,OAAK;KAAE1B,UAAU0B;IAAG,CAAC;IAAAD,QAAAF,MAAA,mBAEfvD,UAAU;IAAAyD,QAAAF,MAAA,eAEdhC,KAAK;IAAAkC,QAAAF,MAAA,YACHI,MAAIpC,MAAMoC,EAAEC,OAAO1C,KAAK,CAAC;IAAAuC,QAAAF,MAAA,YACzBI,MAAIA,EAAEE,gBAAgB,CAAC;IAAA,
|
|
1
|
+
{"version":3,"file":"FilterableSelectMobile.js","names":["css","createSignal","splitProps","SelectMobile","_tmpl2","_template","_tmpl","inputClass","width","height","padding","marginBottom","background","border","borderRadius","color","fontSize","fontFamily","outline","boxSizing","borderColor","noResultsClass","textAlign","defaultItemToValue","item","value","defaultItemToLabel","label","String","defaultFilter","query","itemToLabel","toLowerCase","includes","FilterableSelectMobile","props","local","itemToValue","filter","inputEl","filteredItems","q","trim","list","items","handleOpenChange","isOpen","queueMicrotask","focus","_jsx","Root","_mergeProps","onValueChange","onOpenChange","children","Trigger","placeholder","Content","clearable","clearLabel","backdropClassName","backdropStyle","_el0","cloneNode","_setProp","el","e","target","stopPropagation","preventScroll","length","map","Item","key"],"sources":["../../src/components/FilterableSelectMobile.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createSignal, splitProps } from '@plastic-js/plastic'\nimport { SelectMobile } from './SelectMobile/index.jsx'\n\n// ── Styles ───────────────────────────────────────────────────────────────\nconst inputClass = css({\n\twidth: '100%',\n\theight: '42px',\n\tpadding: '0 14px',\n\tmarginBottom: '6px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\toutline: 'none',\n\tboxSizing: 'border-box',\n\t'&:focus': { borderColor: 'var(--accent)' },\n\t'&::placeholder': { color: 'var(--muted)' },\n})\n\nconst noResultsClass = css({\n\tpadding: '20px 14px',\n\ttextAlign: 'center',\n\tcolor: 'var(--muted)',\n\tfontSize: '14px',\n})\n\n// ── Default accessors ────────────────────────────────────────────────────\nconst defaultItemToValue = item=> item?.value ?? item\nconst defaultItemToLabel = item=> item?.label ?? String(item)\nconst defaultFilter = (item, query, itemToLabel)=> itemToLabel(item).toLowerCase().includes(query)\n\n// ── FilterableSelectMobile ───────────────────────────────────────────────\n//\n// A mobile bottom-sheet select with a filter input at the top of the list.\n// Wraps SelectMobile internally — exposes a flat single-component API.\n//\n// Props:\n// items data array (or getter)\n// value current value (string | getter)\n// onValueChange (value) => void\n// itemToValue (item) => string — default item.value ?? item\n// itemToLabel (item) => string — default item.label ?? String(item)\n// placeholder trigger placeholder text — default \"Select\"\n// filter (item, query, itemToLabel) => boolean — default substring match\n// clearable show a \"clear\" row\n// clearLabel label for the clear row\n// backdropClassName className for the backdrop\n// backdropStyle inline style for the backdrop\nconst FilterableSelectMobile = (props)=> {\n\tconst [local] = splitProps(props, [\n\t\t'items', 'value', 'onValueChange',\n\t\t'itemToValue', 'itemToLabel',\n\t\t'placeholder', 'filter',\n\t\t'clearable', 'clearLabel',\n\t\t'backdropClassName', 'backdropStyle',\n\t])\n\n\tconst itemToValue = local.itemToValue ?? defaultItemToValue\n\tconst itemToLabel = local.itemToLabel ?? defaultItemToLabel\n\tconst filter = local.filter ?? defaultFilter\n\n\tconst query = createSignal('')\n\tlet inputEl = null\n\n\t// Reactive filter — recomputes on typing and items changes.\n\tconst filteredItems = ()=> {\n\t\tconst q = query().trim().toLowerCase()\n\t\tconst list = typeof local.items === 'function' ? local.items() : (local.items ?? [])\n\t\treturn q ? list.filter(item=> filter(item, q, itemToLabel)) : list\n\t}\n\n\t// Auto-focus the input when the sheet opens; clear query on close.\n\tconst handleOpenChange = (isOpen)=> {\n\t\tif (isOpen){\n\t\t\tqueueMicrotask(()=> inputEl?.focus())\n\t\t} else {\n\t\t\tquery('')\n\t\t}\n\t}\n\n\treturn (\n\t\t<SelectMobile.Root\n\t\t\tvalue={local.value}\n\t\t\tonValueChange={local.onValueChange}\n\t\t\titems={local.items}\n\t\t\titemToValue={itemToValue}\n\t\t\titemToLabel={itemToLabel}\n\t\t\tonOpenChange={handleOpenChange}\n\t\t>\n\t\t\t<SelectMobile.Trigger placeholder={local.placeholder} />\n\t\t\t<SelectMobile.Content\n\t\t\t\tclearable={local.clearable}\n\t\t\t\tclearLabel={local.clearLabel}\n\t\t\t\tbackdropClassName={local.backdropClassName}\n\t\t\t\tbackdropStyle={local.backdropStyle}\n\t\t\t>\n\t\t\t\t<input\n\t\t\t\t\tref={el=> { inputEl = el }}\n\t\t\t\t\ttype='text'\n\t\t\t\t\tclassName={inputClass}\n\t\t\t\t\tplaceholder='Filter…'\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tonInput={e=> query(e.target.value)}\n\t\t\t\t\tonClick={e=> e.stopPropagation()}\n\t\t\t\t\tonPointerDown={e=> {\n\t\t\t\t\t\t// Defense-in-depth for Chrome iOS (WebKit) focus-lock bug.\n\t\t\t\t\t\t// The primary fix is in SelectMobile.Content (no <Portal>).\n\t\t\t\t\t\t// This handler ensures focus moves to the input even if a\n\t\t\t\t\t\t// previous button element still holds focus.\n\t\t\t\t\t\te.target.focus({ preventScroll: true })\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t{()=> {\n\t\t\t\t\tconst list = filteredItems()\n\t\t\t\t\tif (list.length === 0){\n\t\t\t\t\t\treturn <div className={noResultsClass}>No results</div>\n\t\t\t\t\t}\n\t\t\t\t\treturn list.map(item => (\n\t\t\t\t\t\t<SelectMobile.Item item={item} key={itemToValue(item)} />\n\t\t\t\t\t))\n\t\t\t\t}}\n\t\t\t</SelectMobile.Content>\n\t\t</SelectMobile.Root>\n\t)\n}\n\nexport default FilterableSelectMobile"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import Icon from "../Icon.js";
|
|
|
2
2
|
import { part } from "./anatomy.js";
|
|
3
3
|
import { Fragment, jsx, mergeProps, setProp, template } from "@plastic-js/plastic/jsx-runtime";
|
|
4
4
|
import { css } from "@emotion/css";
|
|
5
|
-
import { Loop,
|
|
5
|
+
import { Loop, createContext, createEffect, createSignal, splitProps, useContext } from "@plastic-js/plastic";
|
|
6
6
|
//#region src/components/SelectMobile/index.jsx
|
|
7
7
|
var _tmpl = template("<span></span>");
|
|
8
8
|
var chevronDownSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>";
|
|
@@ -202,12 +202,13 @@ var Trigger = (props) => {
|
|
|
202
202
|
"className",
|
|
203
203
|
"children"
|
|
204
204
|
]);
|
|
205
|
-
return jsx("
|
|
205
|
+
return jsx("div", mergeProps(() => part("trigger"), {
|
|
206
206
|
get className() {
|
|
207
207
|
return `${triggerClass} ${local.className || ""}`;
|
|
208
208
|
},
|
|
209
209
|
onClick: () => ctx.open(true),
|
|
210
|
-
|
|
210
|
+
role: "button",
|
|
211
|
+
tabIndex: 0
|
|
211
212
|
}, rest, { children: () => local.children ?? jsx(Fragment, { children: [jsx("span", mergeProps(() => part("triggerValue"), {
|
|
212
213
|
get className() {
|
|
213
214
|
return `${triggerValueClass} ${ctx.selectedItem() ? "" : triggerPlaceholderClass}`;
|
|
@@ -252,7 +253,7 @@ var Content = (props) => {
|
|
|
252
253
|
"backdropStyle",
|
|
253
254
|
"children"
|
|
254
255
|
]);
|
|
255
|
-
return jsx(
|
|
256
|
+
return jsx("div", mergeProps(() => part("positioner"), {
|
|
256
257
|
"aria-hidden": () => !ctx.open(),
|
|
257
258
|
get className() {
|
|
258
259
|
return `${overlayClass} ${ctx.open() ? openClass : ""}`;
|
|
@@ -295,7 +296,7 @@ var Content = (props) => {
|
|
|
295
296
|
}))
|
|
296
297
|
}))] })
|
|
297
298
|
}))] }))]
|
|
298
|
-
}))
|
|
299
|
+
}));
|
|
299
300
|
};
|
|
300
301
|
var SelectMobile = Object.assign(Root, {
|
|
301
302
|
Root,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["css","Loop","Portal","createContext","createEffect","createSignal","splitProps","useContext","Icon","part","_tmpl","_template","chevronDownSvg","checkSvg","triggerClass","flexShrink","width","height","display","alignItems","justifyContent","gap","background","border","borderRadius","padding","color","fontSize","fontFamily","textAlign","outline","cursor","borderColor","triggerValueClass","overflow","textOverflow","whiteSpace","triggerPlaceholderClass","triggerIndicatorClass","overlayClass","position","inset","zIndex","flexDirection","pointerEvents","backdropClass","opacity","transition","sheetClass","maxHeight","borderTop","boxShadow","paddingBottom","transform","openClass","grabberClass","grabberBarClass","listClass","overflowY","WebkitOverflowScrolling","itemClass","itemIndicatorClass","SelectMobileContext","useSelectMobile","ctx","Error","read","source","Root","props","local","rest","internalOpen","defaultOpen","open","v","undefined","onOpenChange","itemToValue","item","value","itemToLabel","label","items","isSelected","String","selectedItem","find","setValue","onValueChange","onKey","e","key","document","addEventListener","prevOverflow","body","style","removeEventListener","_jsx","Provider","_mergeProps","children","Trigger","className","onClick","type","_Fragment","placeholder","svg","Item","data-selected","Content","aria-hidden","backdropClassName","backdropStyle","role","_el0","cloneNode","_setProp","clearable","clearLabel","each","SelectMobile","Object","assign"],"sources":["../../../src/components/SelectMobile/index.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport {\n\tLoop, Portal, createContext, createEffect, createSignal, splitProps, useContext,\n} from '@plastic-js/plastic'\nimport Icon from '../Icon.jsx'\nimport { part } from './anatomy.js'\n\nconst chevronDownSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>'\nconst checkSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>'\n\nconst triggerClass = css({\n\tflexShrink: 0,\n\twidth: '100%',\n\theight: '44px',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'space-between',\n\tgap: '4px',\n\tbackground: 'var(--bg, rgba(0,0,0,0.2))',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tpadding: '0 10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '15px',\n\tfontFamily: 'inherit',\n\ttextAlign: 'left',\n\toutline: 'none',\n\tcursor: 'pointer',\n\t'&:focus-visible': { borderColor: 'var(--accent)' },\n})\n\nconst triggerValueClass = css({\n\toverflow: 'hidden',\n\ttextOverflow: 'ellipsis',\n\twhiteSpace: 'nowrap',\n})\n\nconst triggerPlaceholderClass = css({\n\tcolor: 'var(--muted)',\n})\n\nconst triggerIndicatorClass = css({\n\tflexShrink: 0,\n\tcolor: 'var(--muted)',\n\tdisplay: 'flex',\n\t'& svg': { width: '16px', height: '16px' },\n})\n\nconst overlayClass = css({\n\tposition: 'fixed',\n\tinset: 0,\n\tzIndex: 1000,\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tjustifyContent: 'flex-end',\n\tpointerEvents: 'none',\n})\n\nconst backdropClass = css({\n\tposition: 'absolute',\n\tinset: 0,\n\tbackground: 'rgba(0,0,0,0.5)',\n\topacity: 0,\n\ttransition: 'opacity 240ms ease',\n})\n\nconst sheetClass = css({\n\tposition: 'relative',\n\twidth: '100%',\n\tmaxHeight: '70vh',\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tbackground: 'var(--surface)',\n\tborderTop: '1px solid var(--border)',\n\tborderRadius: '18px 18px 0 0',\n\tboxShadow: '0 -8px 32px rgba(0,0,0,0.4)',\n\tpaddingBottom: 'env(safe-area-inset-bottom, 0px)',\n\ttransform: 'translateY(100%)',\n\ttransition: 'transform 280ms cubic-bezier(0.32, 0.72, 0, 1)',\n})\n\nconst openClass = css({\n\tpointerEvents: 'auto',\n\t[`& .${backdropClass}`]: { opacity: 1 },\n\t[`& .${sheetClass}`]: { transform: 'translateY(0)' },\n})\n\nconst grabberClass = css({\n\tflexShrink: 0,\n\tdisplay: 'flex',\n\tjustifyContent: 'center',\n\tpadding: '10px 0 4px',\n})\n\nconst grabberBarClass = css({\n\twidth: '36px',\n\theight: '4px',\n\tborderRadius: '999px',\n\tbackground: 'var(--border)',\n})\n\nconst listClass = css({\n\toverflowY: 'auto',\n\tWebkitOverflowScrolling: 'touch',\n\tpadding: '0 8px 8px',\n})\n\nconst itemClass = css({\n\twidth: '100%',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'space-between',\n\tgap: '10px',\n\theight: '52px',\n\tpadding: '0 14px',\n\tbackground: 'transparent',\n\tborder: 'none',\n\tborderRadius: '12px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\ttextAlign: 'left',\n\tcursor: 'pointer',\n\t'&:active': { background: 'rgba(255,255,255,0.06)' },\n})\n\nconst itemIndicatorClass = css({\n\tflexShrink: 0,\n\tcolor: 'var(--accent)',\n\tdisplay: 'flex',\n\t'& svg': { width: '18px', height: '18px' },\n})\n\nconst SelectMobileContext = createContext(null)\n\nconst useSelectMobile = ()=> {\n\tconst ctx = useContext(SelectMobileContext)\n\tif (!ctx){ throw new Error('SelectMobile parts must be used inside <SelectMobile.Root>') }\n\treturn ctx\n}\n\nconst read = (source)=> {\n\treturn typeof source === 'function' ? source() : source\n}\n\n// <SelectMobile.Root> — holds selection + open state, resolves item -> value/label.\n// Props:\n// value current value (string | getter)\n// onValueChange (value) => void — called when an item is chosen\n// items data array (or getter) supplied by the consumer\n// itemToValue (item) => string — default item.value\n// itemToLabel (item) => node — default item.label\n// open controlled open state (getter) — when provided, the component\n// is controlled and you must update it via onOpenChange\n// defaultOpen initial open state for uncontrolled mode (default false)\n// onOpenChange (isOpen) => void — called when open state changes\nconst Root = (props)=> {\n\tconst [local, rest] = splitProps(props, [\n\t\t'value', 'onValueChange', 'items', 'itemToValue', 'itemToLabel',\n\t\t'open', 'defaultOpen', 'onOpenChange', 'children',\n\t])\n\tconst internalOpen = createSignal(local.defaultOpen ?? false)\n\n\tconst open = (v)=> {\n\t\tif (v === undefined){\n\t\t\t// getter — controlled if `open` prop is provided, else internal\n\t\t\treturn local.open !== undefined ? read(local.open) : internalOpen()\n\t\t}\n\t\t// setter\n\t\tif (local.open !== undefined){\n\t\t\tlocal.onOpenChange?.(v)\n\t\t} else {\n\t\t\tinternalOpen(v)\n\t\t\tlocal.onOpenChange?.(v)\n\t\t}\n\t}\n\n\tconst itemToValue = (item)=> {\n\t\tif (item == null){ return undefined }\n\t\treturn local.itemToValue ? local.itemToValue(item) : item.value\n\t}\n\tconst itemToLabel = (item)=> {\n\t\tif (item == null){ return undefined }\n\t\treturn local.itemToLabel ? local.itemToLabel(item) : item.label\n\t}\n\tconst items = ()=> read(local.items) || []\n\tconst value = ()=> read(local.value) ?? ''\n\tconst isSelected = v=> String(value()) === String(v)\n\tconst selectedItem = ()=> items().find(item=> isSelected(itemToValue(item)))\n\n\tconst setValue = (v)=> {\n\t\tlocal.onValueChange?.(v)\n\t\topen(false)\n\t}\n\n\tcreateEffect(()=> {\n\t\tif (!open()){ return undefined }\n\t\tconst onKey = (e)=> { if (e.key === 'Escape'){ open(false) } }\n\t\tdocument.addEventListener('keydown', onKey)\n\t\tconst prevOverflow = document.body.style.overflow\n\t\tdocument.body.style.overflow = 'hidden'\n\t\treturn ()=> {\n\t\t\tdocument.removeEventListener('keydown', onKey)\n\t\t\tdocument.body.style.overflow = prevOverflow\n\t\t}\n\t})\n\n\t// Plastic components run once (fine-grained reactivity), so this object is\n\t// created a single time per mount — the React \"stable value\" rule misfires.\n\t// eslint-disable-next-line react/jsx-no-constructed-context-values\n\tconst ctx = {\n\t\topen, value, items, itemToValue, itemToLabel, isSelected, selectedItem, setValue,\n\t}\n\n\treturn (\n\t\t<SelectMobileContext.Provider value={ctx}>\n\t\t\t<div {...part('root')} {...rest}>\n\t\t\t\t{local.children}\n\t\t\t</div>\n\t\t</SelectMobileContext.Provider>\n\t)\n}\n\n// <SelectMobile.Trigger> — the button that opens the sheet. Shows the selected\n// item's label (or `placeholder`). Pass children to fully customize.\nconst Trigger = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, ['placeholder', 'className', 'children'])\n\n\treturn (\n\t\t<button\n\t\t\t{...part('trigger')}\n\t\t\tclassName={`${triggerClass} ${local.className || ''}`}\n\t\t\tonClick={()=> ctx.open(true)}\n\t\t\ttype='button'\n\t\t\t{...rest}\n\t\t>\n\t\t\t{local.children ?? (\n\t\t\t\t<>\n\t\t\t\t\t<span\n\t\t\t\t\t\t{...part('triggerValue')}\n\t\t\t\t\t\tclassName={`${triggerValueClass} ${ctx.selectedItem() ? '' : triggerPlaceholderClass}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{()=> {\n\t\t\t\t\t\t\tconst item = ctx.selectedItem()\n\t\t\t\t\t\t\treturn item !== undefined ? ctx.itemToLabel(item) : local.placeholder ?? 'Select'\n\t\t\t\t\t\t}}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span {...part('triggerIndicator')} className={triggerIndicatorClass}>\n\t\t\t\t\t\t<Icon svg={chevronDownSvg} />\n\t\t\t\t\t</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</button>\n\t)\n}\n\n// <SelectMobile.Item> — a selectable row. Provide `item` (resolved via Root's\n// accessors) or an explicit `value` + children for custom content.\nconst Item = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, ['item', 'value', 'className', 'children'])\n\tconst value = ()=> local.item !== undefined ? ctx.itemToValue(local.item) : local.value\n\n\treturn (\n\t\t<button\n\t\t\t{...part('item')}\n\t\t\tclassName={`${itemClass} ${local.className || ''}`}\n\t\t\tdata-selected={()=> ctx.isSelected(value()) ? '' : undefined}\n\t\t\tonClick={()=> ctx.setValue(value())}\n\t\t\ttype='button'\n\t\t\t{...rest}\n\t\t>\n\t\t\t<span {...part('itemText')}>\n\t\t\t\t{local.children ?? (local.item !== undefined && ctx.itemToLabel(local.item))}\n\t\t\t</span>\n\t\t\t{()=> ctx.isSelected(value()) && (\n\t\t\t\t<span {...part('itemIndicator')} className={itemIndicatorClass}>\n\t\t\t\t\t<Icon svg={checkSvg} />\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</button>\n\t)\n}\n\n// <SelectMobile.Content> — the bottom sheet. With no children it auto-renders one\n// SelectMobile.Item per Root item; pass `clearable` to prepend a \"clear\" row.\n// Props:\n// clearable show a \"clear\" row at the top\n// clearLabel label for the clear row (default \"None\")\n// backdropClassName className passed to the backdrop (higher priority)\n// backdropStyle inline style passed to the backdrop (higher priority)\nconst Content = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, [\n\t\t'clearable', 'clearLabel', 'className',\n\t\t'backdropClassName', 'backdropStyle', 'children',\n\t])\n\n\treturn (\n\t\t<Portal>\n\t\t\t<div\n\t\t\t\t{...part('positioner')}\n\t\t\t\taria-hidden={()=> !ctx.open()}\n\t\t\t\tclassName={`${overlayClass} ${ctx.open() ? openClass : ''}`}\n\t\t\t>\n\t\t\t\t<div {...part('backdrop')} className={`${backdropClass} ${local.backdropClassName || ''}`} style={local.backdropStyle} onClick={()=> ctx.open(false)} />\n\t\t\t\t<div {...part('content')} className={`${sheetClass} ${local.className || ''}`} role='dialog' {...rest}>\n\t\t\t\t\t<div {...part('grabber')} className={grabberClass} onClick={()=> ctx.open(false)}>\n\t\t\t\t\t\t<span className={grabberBarClass} />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div {...part('list')} className={listClass}>\n\t\t\t\t\t\t{local.children ?? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t{()=> local.clearable && (\n\t\t\t\t\t\t\t\t\t<Item value=''>\n\t\t\t\t\t\t\t\t\t\t{local.clearLabel ?? 'None'}\n\t\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t<Loop each={ctx.items}>\n\t\t\t\t\t\t\t\t\t{item=> <Item item={item} key={ctx.itemToValue(item)} />}\n\t\t\t\t\t\t\t\t</Loop>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Portal>\n\t)\n}\n\nconst SelectMobile = Object.assign(Root, {\n\tRoot, Trigger, Content, Item,\n})\n\nexport default SelectMobile\nexport {\n\tSelectMobile, Root, Trigger, Content, Item,\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["css","Loop","Portal","createContext","createEffect","createSignal","splitProps","useContext","Icon","part","_tmpl","_template","chevronDownSvg","checkSvg","triggerClass","flexShrink","width","height","display","alignItems","justifyContent","gap","background","border","borderRadius","padding","color","fontSize","fontFamily","textAlign","outline","cursor","borderColor","triggerValueClass","overflow","textOverflow","whiteSpace","triggerPlaceholderClass","triggerIndicatorClass","overlayClass","position","inset","zIndex","flexDirection","pointerEvents","backdropClass","opacity","transition","sheetClass","maxHeight","borderTop","boxShadow","paddingBottom","transform","openClass","grabberClass","grabberBarClass","listClass","overflowY","WebkitOverflowScrolling","itemClass","itemIndicatorClass","SelectMobileContext","useSelectMobile","ctx","Error","read","source","Root","props","local","rest","internalOpen","defaultOpen","open","v","undefined","onOpenChange","itemToValue","item","value","itemToLabel","label","items","isSelected","String","selectedItem","find","setValue","onValueChange","onKey","e","key","document","addEventListener","prevOverflow","body","style","removeEventListener","_jsx","Provider","_mergeProps","children","Trigger","className","onClick","role","tabIndex","_Fragment","placeholder","svg","Item","data-selected","type","Content","aria-hidden","backdropClassName","backdropStyle","_el0","cloneNode","_setProp","clearable","clearLabel","each","SelectMobile","Object","assign"],"sources":["../../../src/components/SelectMobile/index.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport {\n\tLoop, Portal, createContext, createEffect, createSignal, splitProps, useContext,\n} from '@plastic-js/plastic'\nimport Icon from '../Icon.jsx'\nimport { part } from './anatomy.js'\n\nconst chevronDownSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>'\nconst checkSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>'\n\nconst triggerClass = css({\n\tflexShrink: 0,\n\twidth: '100%',\n\theight: '44px',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'space-between',\n\tgap: '4px',\n\tbackground: 'var(--bg, rgba(0,0,0,0.2))',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tpadding: '0 10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '15px',\n\tfontFamily: 'inherit',\n\ttextAlign: 'left',\n\toutline: 'none',\n\tcursor: 'pointer',\n\t'&:focus-visible': { borderColor: 'var(--accent)' },\n})\n\nconst triggerValueClass = css({\n\toverflow: 'hidden',\n\ttextOverflow: 'ellipsis',\n\twhiteSpace: 'nowrap',\n})\n\nconst triggerPlaceholderClass = css({\n\tcolor: 'var(--muted)',\n})\n\nconst triggerIndicatorClass = css({\n\tflexShrink: 0,\n\tcolor: 'var(--muted)',\n\tdisplay: 'flex',\n\t'& svg': { width: '16px', height: '16px' },\n})\n\nconst overlayClass = css({\n\tposition: 'fixed',\n\tinset: 0,\n\tzIndex: 1000,\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tjustifyContent: 'flex-end',\n\tpointerEvents: 'none',\n})\n\nconst backdropClass = css({\n\tposition: 'absolute',\n\tinset: 0,\n\tbackground: 'rgba(0,0,0,0.5)',\n\topacity: 0,\n\ttransition: 'opacity 240ms ease',\n})\n\nconst sheetClass = css({\n\tposition: 'relative',\n\twidth: '100%',\n\tmaxHeight: '70vh',\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tbackground: 'var(--surface)',\n\tborderTop: '1px solid var(--border)',\n\tborderRadius: '18px 18px 0 0',\n\tboxShadow: '0 -8px 32px rgba(0,0,0,0.4)',\n\tpaddingBottom: 'env(safe-area-inset-bottom, 0px)',\n\ttransform: 'translateY(100%)',\n\ttransition: 'transform 280ms cubic-bezier(0.32, 0.72, 0, 1)',\n})\n\nconst openClass = css({\n\tpointerEvents: 'auto',\n\t[`& .${backdropClass}`]: { opacity: 1 },\n\t[`& .${sheetClass}`]: { transform: 'translateY(0)' },\n})\n\nconst grabberClass = css({\n\tflexShrink: 0,\n\tdisplay: 'flex',\n\tjustifyContent: 'center',\n\tpadding: '10px 0 4px',\n})\n\nconst grabberBarClass = css({\n\twidth: '36px',\n\theight: '4px',\n\tborderRadius: '999px',\n\tbackground: 'var(--border)',\n})\n\nconst listClass = css({\n\toverflowY: 'auto',\n\tWebkitOverflowScrolling: 'touch',\n\tpadding: '0 8px 8px',\n})\n\nconst itemClass = css({\n\twidth: '100%',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'space-between',\n\tgap: '10px',\n\theight: '52px',\n\tpadding: '0 14px',\n\tbackground: 'transparent',\n\tborder: 'none',\n\tborderRadius: '12px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\ttextAlign: 'left',\n\tcursor: 'pointer',\n\t'&:active': { background: 'rgba(255,255,255,0.06)' },\n})\n\nconst itemIndicatorClass = css({\n\tflexShrink: 0,\n\tcolor: 'var(--accent)',\n\tdisplay: 'flex',\n\t'& svg': { width: '18px', height: '18px' },\n})\n\nconst SelectMobileContext = createContext(null)\n\nconst useSelectMobile = ()=> {\n\tconst ctx = useContext(SelectMobileContext)\n\tif (!ctx){ throw new Error('SelectMobile parts must be used inside <SelectMobile.Root>') }\n\treturn ctx\n}\n\nconst read = (source)=> {\n\treturn typeof source === 'function' ? source() : source\n}\n\n// <SelectMobile.Root> — holds selection + open state, resolves item -> value/label.\n// Props:\n// value current value (string | getter)\n// onValueChange (value) => void — called when an item is chosen\n// items data array (or getter) supplied by the consumer\n// itemToValue (item) => string — default item.value\n// itemToLabel (item) => node — default item.label\n// open controlled open state (getter) — when provided, the component\n// is controlled and you must update it via onOpenChange\n// defaultOpen initial open state for uncontrolled mode (default false)\n// onOpenChange (isOpen) => void — called when open state changes\nconst Root = (props)=> {\n\tconst [local, rest] = splitProps(props, [\n\t\t'value', 'onValueChange', 'items', 'itemToValue', 'itemToLabel',\n\t\t'open', 'defaultOpen', 'onOpenChange', 'children',\n\t])\n\tconst internalOpen = createSignal(local.defaultOpen ?? false)\n\n\tconst open = (v)=> {\n\t\tif (v === undefined){\n\t\t\t// getter — controlled if `open` prop is provided, else internal\n\t\t\treturn local.open !== undefined ? read(local.open) : internalOpen()\n\t\t}\n\t\t// setter\n\t\tif (local.open !== undefined){\n\t\t\tlocal.onOpenChange?.(v)\n\t\t} else {\n\t\t\tinternalOpen(v)\n\t\t\tlocal.onOpenChange?.(v)\n\t\t}\n\t}\n\n\tconst itemToValue = (item)=> {\n\t\tif (item == null){ return undefined }\n\t\treturn local.itemToValue ? local.itemToValue(item) : item.value\n\t}\n\tconst itemToLabel = (item)=> {\n\t\tif (item == null){ return undefined }\n\t\treturn local.itemToLabel ? local.itemToLabel(item) : item.label\n\t}\n\tconst items = ()=> read(local.items) || []\n\tconst value = ()=> read(local.value) ?? ''\n\tconst isSelected = v=> String(value()) === String(v)\n\tconst selectedItem = ()=> items().find(item=> isSelected(itemToValue(item)))\n\n\tconst setValue = (v)=> {\n\t\tlocal.onValueChange?.(v)\n\t\topen(false)\n\t}\n\n\tcreateEffect(()=> {\n\t\tif (!open()){ return undefined }\n\t\tconst onKey = (e)=> { if (e.key === 'Escape'){ open(false) } }\n\t\tdocument.addEventListener('keydown', onKey)\n\t\tconst prevOverflow = document.body.style.overflow\n\t\tdocument.body.style.overflow = 'hidden'\n\t\treturn ()=> {\n\t\t\tdocument.removeEventListener('keydown', onKey)\n\t\t\tdocument.body.style.overflow = prevOverflow\n\t\t}\n\t})\n\n\t// Plastic components run once (fine-grained reactivity), so this object is\n\t// created a single time per mount — the React \"stable value\" rule misfires.\n\t// eslint-disable-next-line react/jsx-no-constructed-context-values\n\tconst ctx = {\n\t\topen, value, items, itemToValue, itemToLabel, isSelected, selectedItem, setValue,\n\t}\n\n\treturn (\n\t\t<SelectMobileContext.Provider value={ctx}>\n\t\t\t<div {...part('root')} {...rest}>\n\t\t\t\t{local.children}\n\t\t\t</div>\n\t\t</SelectMobileContext.Provider>\n\t)\n}\n\n// <SelectMobile.Trigger> — the button that opens the sheet. Shows the selected\n// item's label (or `placeholder`). Pass children to fully customize.\n//\n// NOTE: Uses <div role=\"button\"> instead of a native <button> as a\n// defense-in-depth measure against a Chrome iOS (WebKit) focus-lock bug.\n//\n// The primary fix is in <SelectMobile.Content>: the sheet is rendered inline\n// (no <Portal>) so it stays inside the parent Dialog's focus-trap boundary.\n// However, the <div role=\"button\"> is kept as an additional safeguard — in\n// WebKit, tapping a <button> inside a scrollable container with\n// -webkit-overflow-scrolling:touch can pin activeElement to the button,\n// causing subsequent focus() calls on the filter <input> to be silently\n// ignored. A <div role=\"button\"> is semantically equivalent for accessibility\n// but does not trigger this WebKit focus-lock behaviour.\nconst Trigger = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, ['placeholder', 'className', 'children'])\n\n\treturn (\n\t\t<div\n\t\t\t{...part('trigger')}\n\t\t\tclassName={`${triggerClass} ${local.className || ''}`}\n\t\t\tonClick={()=> ctx.open(true)}\n\t\t\trole='button'\n\t\t\ttabIndex={0}\n\t\t\t{...rest}\n\t\t>\n\t\t\t{local.children ?? (\n\t\t\t\t<>\n\t\t\t\t\t<span\n\t\t\t\t\t\t{...part('triggerValue')}\n\t\t\t\t\t\tclassName={`${triggerValueClass} ${ctx.selectedItem() ? '' : triggerPlaceholderClass}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{()=> {\n\t\t\t\t\t\t\tconst item = ctx.selectedItem()\n\t\t\t\t\t\t\treturn item !== undefined ? ctx.itemToLabel(item) : local.placeholder ?? 'Select'\n\t\t\t\t\t\t}}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span {...part('triggerIndicator')} className={triggerIndicatorClass}>\n\t\t\t\t\t\t<Icon svg={chevronDownSvg} />\n\t\t\t\t\t</span>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n\n// <SelectMobile.Item> — a selectable row. Provide `item` (resolved via Root's\n// accessors) or an explicit `value` + children for custom content.\nconst Item = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, ['item', 'value', 'className', 'children'])\n\tconst value = ()=> local.item !== undefined ? ctx.itemToValue(local.item) : local.value\n\n\treturn (\n\t\t<button\n\t\t\t{...part('item')}\n\t\t\tclassName={`${itemClass} ${local.className || ''}`}\n\t\t\tdata-selected={()=> ctx.isSelected(value()) ? '' : undefined}\n\t\t\tonClick={()=> ctx.setValue(value())}\n\t\t\ttype='button'\n\t\t\t{...rest}\n\t\t>\n\t\t\t<span {...part('itemText')}>\n\t\t\t\t{local.children ?? (local.item !== undefined && ctx.itemToLabel(local.item))}\n\t\t\t</span>\n\t\t\t{()=> ctx.isSelected(value()) && (\n\t\t\t\t<span {...part('itemIndicator')} className={itemIndicatorClass}>\n\t\t\t\t\t<Icon svg={checkSvg} />\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</button>\n\t)\n}\n\n// <SelectMobile.Content> — the bottom sheet. With no children it auto-renders one\n// SelectMobile.Item per Root item; pass `clearable` to prepend a \"clear\" row.\n// Props:\n// clearable show a \"clear\" row at the top\n// clearLabel label for the clear row (default \"None\")\n// backdropClassName className passed to the backdrop (higher priority)\n// backdropStyle inline style passed to the backdrop (higher priority)\n//\n// NOTE: No <Portal> wrapper. The overlay uses `position: fixed; inset: 0;\n// z-index: 1000` so it still covers the viewport without being portaled to\n// document.body. Rendering inline keeps the sheet inside the nearest focus-trap\n// boundary (e.g. a parent Dialog), which prevents zag-js / ark focus traps from\n// fighting the filter input's auto-focus. This is the primary fix for the\n// Chrome iOS focus-lock bug when SelectMobile is nested inside a Dialog.\nconst Content = (props)=> {\n\tconst ctx = useSelectMobile()\n\tconst [local, rest] = splitProps(props, [\n\t\t'clearable', 'clearLabel', 'className',\n\t\t'backdropClassName', 'backdropStyle', 'children',\n\t])\n\treturn (\n\t\t<div\n\t\t\t{...part('positioner')}\n\t\t\taria-hidden={()=> !ctx.open()}\n\t\t\tclassName={`${overlayClass} ${ctx.open() ? openClass : ''}`}\n\t\t>\n\t\t\t<div {...part('backdrop')} className={`${backdropClass} ${local.backdropClassName || ''}`} style={local.backdropStyle} onClick={()=> ctx.open(false)} />\n\t\t\t<div {...part('content')} className={`${sheetClass} ${local.className || ''}`} role='dialog' {...rest}>\n\t\t\t\t<div {...part('grabber')} className={grabberClass} onClick={()=> ctx.open(false)}>\n\t\t\t\t\t<span className={grabberBarClass} />\n\t\t\t\t</div>\n\t\t\t\t<div {...part('list')} className={listClass}>\n\t\t\t\t\t{local.children ?? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{()=> local.clearable && (\n\t\t\t\t\t\t\t\t<Item value=''>\n\t\t\t\t\t\t\t\t\t{local.clearLabel ?? 'None'}\n\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<Loop each={ctx.items}>\n\t\t\t\t\t\t\t\t{item=> <Item item={item} key={ctx.itemToValue(item)} />}\n\t\t\t\t\t\t\t</Loop>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst SelectMobile = Object.assign(Root, {\n\tRoot, Trigger, Content, Item,\n})\n\nexport default SelectMobile\nexport {\n\tSelectMobile, Root, Trigger, Content, Item,\n}"],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ import { createEffect, createSignal } from "@plastic-js/plastic";
|
|
|
5
5
|
var _tmpl2 = template("<button type=\"button\"></button>");
|
|
6
6
|
var _tmpl = template("<div><div data-dragging=\"false\"><div></div><div></div></div></div>");
|
|
7
7
|
var ACTIONS_WIDTH = 160;
|
|
8
|
+
var VELOCITY_THRESHOLD = .5;
|
|
9
|
+
var RUBBER_BAND_LIMIT = 50;
|
|
8
10
|
var wrapperClass = css`
|
|
9
11
|
position: relative;
|
|
10
12
|
overflow: hidden;
|
|
@@ -15,7 +17,7 @@ var trackClass = css`
|
|
|
15
17
|
display: flex;
|
|
16
18
|
align-items: stretch;
|
|
17
19
|
will-change: transform;
|
|
18
|
-
transition: transform
|
|
20
|
+
transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
19
21
|
touch-action: pan-y;
|
|
20
22
|
&[data-dragging="true"] { transition: none; }
|
|
21
23
|
`;
|
|
@@ -43,8 +45,11 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
43
45
|
let trackEl = null;
|
|
44
46
|
let startX = 0;
|
|
45
47
|
let startY = 0;
|
|
48
|
+
let lastX = 0;
|
|
49
|
+
let lastTime = 0;
|
|
46
50
|
let baseOffset = 0;
|
|
47
51
|
let currentOffset = 0;
|
|
52
|
+
let velocity = 0;
|
|
48
53
|
let dragging = false;
|
|
49
54
|
let axisLocked = false;
|
|
50
55
|
let horizontal = false;
|
|
@@ -55,12 +60,13 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
55
60
|
const applyTransform = (px) => {
|
|
56
61
|
if (trackEl) trackEl.style.transform = `translateX(${px}px)`;
|
|
57
62
|
};
|
|
63
|
+
const setDragging = (v) => {
|
|
64
|
+
if (trackEl) trackEl.dataset.dragging = String(v);
|
|
65
|
+
};
|
|
58
66
|
const snap = (toOpen) => {
|
|
59
67
|
currentOffset = toOpen ? -160 : 0;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
applyTransform(currentOffset);
|
|
63
|
-
}
|
|
68
|
+
setDragging(false);
|
|
69
|
+
applyTransform(currentOffset);
|
|
64
70
|
onOpenChange?.(toOpen);
|
|
65
71
|
isOpen(toOpen);
|
|
66
72
|
};
|
|
@@ -69,21 +75,23 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
69
75
|
if (currentActive !== void 0 && currentActive !== thisId && isOpen()) {
|
|
70
76
|
isOpen(false);
|
|
71
77
|
currentOffset = 0;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
applyTransform(0);
|
|
75
|
-
}
|
|
78
|
+
setDragging(false);
|
|
79
|
+
applyTransform(0);
|
|
76
80
|
}
|
|
77
81
|
});
|
|
78
82
|
const onPointerDown = (e) => {
|
|
79
83
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
80
84
|
startX = e.clientX;
|
|
81
85
|
startY = e.clientY;
|
|
86
|
+
lastX = e.clientX;
|
|
87
|
+
lastTime = performance.now();
|
|
82
88
|
baseOffset = isOpen() ? -160 : 0;
|
|
89
|
+
velocity = 0;
|
|
83
90
|
dragging = true;
|
|
84
91
|
axisLocked = false;
|
|
85
92
|
horizontal = false;
|
|
86
93
|
moved = false;
|
|
94
|
+
onSwipeStart?.();
|
|
87
95
|
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
88
96
|
};
|
|
89
97
|
const onPointerMove = (e) => {
|
|
@@ -94,13 +102,21 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
94
102
|
if (Math.abs(dx) < 6 && Math.abs(dy) < 6) return;
|
|
95
103
|
horizontal = Math.abs(dx) > Math.abs(dy);
|
|
96
104
|
axisLocked = true;
|
|
97
|
-
if (horizontal
|
|
105
|
+
if (horizontal) setDragging(true);
|
|
98
106
|
}
|
|
99
107
|
if (!horizontal) return;
|
|
100
108
|
moved = true;
|
|
109
|
+
const now = performance.now();
|
|
110
|
+
const dt = now - lastTime;
|
|
111
|
+
if (dt > 0) velocity = (e.clientX - lastX) / dt;
|
|
112
|
+
lastX = e.clientX;
|
|
113
|
+
lastTime = now;
|
|
101
114
|
let next = baseOffset + dx;
|
|
102
|
-
if (next > 0) next =
|
|
103
|
-
if (next < -160)
|
|
115
|
+
if (next > 0) next = RUBBER_BAND_LIMIT * (1 - Math.exp(-next / RUBBER_BAND_LIMIT));
|
|
116
|
+
if (next < -160) {
|
|
117
|
+
const over = -(next + ACTIONS_WIDTH);
|
|
118
|
+
next = -160 - RUBBER_BAND_LIMIT * (1 - Math.exp(-over / RUBBER_BAND_LIMIT));
|
|
119
|
+
}
|
|
104
120
|
currentOffset = next;
|
|
105
121
|
applyTransform(next);
|
|
106
122
|
};
|
|
@@ -109,6 +125,10 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
109
125
|
dragging = false;
|
|
110
126
|
e.currentTarget.releasePointerCapture?.(e.pointerId);
|
|
111
127
|
if (!horizontal) return;
|
|
128
|
+
if (Math.abs(velocity) > VELOCITY_THRESHOLD) {
|
|
129
|
+
snap(velocity < 0);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
112
132
|
snap(currentOffset < -80);
|
|
113
133
|
};
|
|
114
134
|
const handleContentClick = (e) => {
|
|
@@ -135,10 +155,11 @@ var SwipeReveal = ({ actions, children, onSwipeStart, onOpenChange, activeId, th
|
|
|
135
155
|
insert(_el2, () => children);
|
|
136
156
|
setProp(_el2, "className", () => contentClass);
|
|
137
157
|
setProp(_el2, "onClick", () => handleContentClick);
|
|
138
|
-
insert(_el3, () => actions.map((action) => () => {
|
|
158
|
+
insert(_el3, () => actions.map((action, idx) => () => {
|
|
139
159
|
const _el0 = _tmpl2.cloneNode(true);
|
|
140
160
|
insert(_el0, () => action.label);
|
|
141
161
|
setProp(_el0, "className", () => actionBtnClass);
|
|
162
|
+
setProp(_el0, "key", () => action.label ?? idx);
|
|
142
163
|
setProp(_el0, "onClick", () => handleActionClick(action));
|
|
143
164
|
setProp(_el0, "style", () => ({ background: action.color }));
|
|
144
165
|
setProp(_el0, "tabIndex", () => isOpen() ? 0 : -1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SwipeReveal.js","names":["css","createEffect","createSignal","_tmpl2","_template","_tmpl","ACTIONS_WIDTH","SWIPE_THRESHOLD","wrapperClass","trackClass","actionsClass","actionBtnClass","contentClass","SwipeReveal","actions","children","onSwipeStart","onOpenChange","activeId","thisId","isOpen","trackEl","startX","startY","baseOffset","currentOffset","dragging","axisLocked","horizontal","moved","setTrackRef","el","applyTransform","px","style","transform","snap","toOpen","dataset","currentActive","undefined","onPointerDown","e","pointerType","button","clientX","clientY","currentTarget","setPointerCapture","pointerId","onPointerMove","dx","dy","Math","abs","next","onPointerUp","releasePointerCapture","shouldOpen","handleContentClick","stopPropagation","handleActionClick","action","onClick","_el0","cloneNode","_el1","firstChild","_el2","_el3","nextSibling","_insert","_setProp","map","label","background","color"],"sources":["../../src/components/SwipeReveal.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createEffect, createSignal } from '@plastic-js/plastic'\n\nconst ACTIONS_WIDTH = 160\nconst SWIPE_THRESHOLD = ACTIONS_WIDTH / 2\n\nconst wrapperClass = css`\n\tposition: relative;\n\toverflow: hidden;\n\tborder-radius: 12px;\n\tuser-select: none;\n`\n\nconst trackClass = css`\n\tdisplay: flex;\n\talign-items: stretch;\n\twill-change: transform;\n\ttransition: transform 220ms ease;\n\ttouch-action: pan-y;\n\t&[data-dragging=\"true\"] { transition: none; }\n`\n\nconst actionsClass = css`\n\tflex: 0 0 ${ACTIONS_WIDTH}px;\n\tdisplay: flex;\n`\n\nconst actionBtnClass = css`\n\tflex: 1;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder: none;\n\tcolor: #fff;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n\tfont-family: inherit;\n`\n\nconst contentClass = css`\n\tflex: 0 0 100%;\n`\n\nconst SwipeReveal = ({\n\tactions, children, onSwipeStart, onOpenChange, activeId, thisId,\n})=> {\n\tconst isOpen = createSignal(false)\n\n\tlet trackEl = null\n\tlet startX = 0\n\tlet startY = 0\n\tlet baseOffset = 0\n\tlet currentOffset = 0\n\tlet dragging = false\n\tlet axisLocked = false\n\tlet horizontal = false\n\tlet moved = false\n\n\tconst setTrackRef = (el)=> { trackEl = el }\n\n\tconst applyTransform = (px)=> {\n\t\tif (trackEl){ trackEl.style.transform = `translateX(${px}px)` }\n\t}\n\n\tconst snap = (toOpen)=> {\n\t\tcurrentOffset = toOpen ? -ACTIONS_WIDTH : 0\n\t\tif (trackEl){\n\t\t\ttrackEl.dataset.dragging = 'false'\n\t\t\tapplyTransform(currentOffset)\n\t\t}\n\t\tonOpenChange?.(toOpen)\n\t\tisOpen(toOpen)\n\t}\n\n\t// only one card open at a time — close when another card's swipe activates\n\tcreateEffect(()=> {\n\t\tconst currentActive = typeof activeId === 'function' ? activeId() : activeId\n\t\tif (currentActive !== undefined && currentActive !== thisId && isOpen()){\n\t\t\tisOpen(false)\n\t\t\tcurrentOffset = 0\n\t\t\tif (trackEl){\n\t\t\t\ttrackEl.dataset.dragging = 'false'\n\t\t\t\tapplyTransform(0)\n\t\t\t}\n\t\t}\n\t})\n\n\tconst onPointerDown = (e)=> {\n\t\tif (e.pointerType === 'mouse' && e.button !== 0){ return }\n\t\tstartX = e.clientX\n\t\tstartY = e.clientY\n\t\tbaseOffset = isOpen() ? -ACTIONS_WIDTH : 0\n\t\tdragging = true\n\t\taxisLocked = false\n\t\thorizontal = false\n\t\tmoved = false\n\t\te.currentTarget.setPointerCapture?.(e.pointerId)\n\t}\n\n\tconst onPointerMove = (e)=> {\n\t\tif (!dragging){ return }\n\t\tconst dx = e.clientX - startX\n\t\tconst dy = e.clientY - startY\n\t\tif (!axisLocked){\n\t\t\tif (Math.abs(dx) < 6 && Math.abs(dy) < 6){ return }\n\t\t\thorizontal = Math.abs(dx) > Math.abs(dy)\n\t\t\taxisLocked = true\n\t\t\tif (horizontal && trackEl){ trackEl.dataset.dragging = 'true' }\n\t\t}\n\t\tif (!horizontal){ return }\n\t\tmoved = true\n\t\tlet next = baseOffset + dx\n\t\tif (next > 0){ next = 0 }\n\t\tif (next < -ACTIONS_WIDTH){ next = -ACTIONS_WIDTH - (next + ACTIONS_WIDTH) * 0.2 }\n\t\tcurrentOffset = next\n\t\tapplyTransform(next)\n\t}\n\n\tconst onPointerUp = (e)=> {\n\t\tif (!dragging){ return }\n\t\tdragging = false\n\t\te.currentTarget.releasePointerCapture?.(e.pointerId)\n\t\tif (!horizontal){ return }\n\t\tconst shouldOpen = currentOffset < -SWIPE_THRESHOLD\n\t\tsnap(shouldOpen)\n\t}\n\n\tconst handleContentClick = (e)=> {\n\t\tif (moved){ e.stopPropagation(); return }\n\t\tif (isOpen()){ e.stopPropagation(); snap(false); return }\n\t}\n\n\tconst handleActionClick = action=> (e)=> {\n\t\te.stopPropagation()\n\t\tsnap(false)\n\t\taction.onClick?.(e)\n\t}\n\n\treturn (\n\t\t<div className={wrapperClass}>\n\t\t\t<div\n\t\t\t\tclassName={trackClass}\n\t\t\t\tdata-dragging='false'\n\t\t\t\tonPointerCancel={onPointerUp}\n\t\t\t\tonPointerDown={onPointerDown}\n\t\t\t\tonPointerMove={onPointerMove}\n\t\t\t\tonPointerUp={onPointerUp}\n\t\t\t\tref={setTrackRef}\n\t\t\t>\n\t\t\t\t<div className={contentClass} onClick={handleContentClick}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t\t<div className={actionsClass}>\n\t\t\t\t\t{actions.map(action=> (\n\t\t\t\t\t\t// prevent tab focus when actions are hidden off-screen\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tclassName={actionBtnClass}\n\t\t\t\t\t\t\tonClick={handleActionClick(action)}\n\t\t\t\t\t\t\tstyle={{ background: action.color }}\n\t\t\t\t\t\t\ttabIndex={isOpen() ? 0 : -1}\n\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{action.label}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport default SwipeReveal\n"],"mappings":";;;;AACgE,IAAAG,SAAAC,SAAA,mCAAA;AAAA,IAAAC,QAAAD,SAAA,sEAAA;AAEhE,IAAME,gBAAgB;AAGtB,IAAME,eAAeR,GAAG;;;;;;AAOxB,IAAMS,aAAaT,GAAG;;;;;;;;AAStB,IAAMU,eAAeV,GAAG;aACXM,cAAa;;;AAI1B,IAAMK,iBAAiBX,GAAG;;;;;;;;;;;;AAa1B,IAAMY,eAAeZ,GAAG;;;AAIxB,IAAMa,eAAe,EACpBC,SAASC,UAAUC,cAAcC,cAAcC,UAAUC,aACrD;CACJ,MAAMC,SAASlB,aAAa,KAAK;CAEjC,IAAImB,UAAU;CACd,IAAIC,SAAS;CACb,IAAIC,SAAS;CACb,IAAIC,aAAa;CACjB,IAAIC,gBAAgB;CACpB,IAAIC,WAAW;CACf,IAAIC,aAAa;CACjB,IAAIC,aAAa;CACjB,IAAIC,QAAQ;CAEZ,MAAMC,eAAeC,OAAM;EAAEV,UAAUU;CAAG;CAE1C,MAAMC,kBAAkBC,OAAM;EAC7B,IAAIZ,SAAUA,QAAQa,MAAMC,YAAY,cAAcF,GAAE;CACzD;CAEA,MAAMG,QAAQC,WAAU;EACvBZ,gBAAgBY,SAAS,OAAiB;EAC1C,IAAIhB,SAAQ;GACXA,QAAQiB,QAAQZ,WAAW;GAC3BM,eAAeP,aAAa;EAC7B;EACAR,eAAeoB,MAAM;EACrBjB,OAAOiB,MAAM;CACd;CAGApC,mBAAkB;EACjB,MAAMsC,gBAAgB,OAAOrB,aAAa,aAAaA,SAAS,IAAIA;EACpE,IAAIqB,kBAAkBC,KAAAA,KAAaD,kBAAkBpB,UAAUC,OAAO,GAAE;GACvEA,OAAO,KAAK;GACZK,gBAAgB;GAChB,IAAIJ,SAAQ;IACXA,QAAQiB,QAAQZ,WAAW;IAC3BM,eAAe,CAAC;GACjB;EACD;CACD,CAAC;CAED,MAAMS,iBAAiBC,MAAK;EAC3B,IAAIA,EAAEC,gBAAgB,WAAWD,EAAEE,WAAW,GAAI;EAClDtB,SAASoB,EAAEG;EACXtB,SAASmB,EAAEI;EACXtB,aAAaJ,OAAO,IAAI,OAAiB;EACzCM,WAAW;EACXC,aAAa;EACbC,aAAa;EACbC,QAAQ;EACRa,EAAEK,cAAcC,oBAAoBN,EAAEO,SAAS;CAChD;CAEA,MAAMC,iBAAiBR,MAAK;EAC3B,IAAI,CAAChB,UAAW;EAChB,MAAMyB,KAAKT,EAAEG,UAAUvB;EACvB,MAAM8B,KAAKV,EAAEI,UAAUvB;EACvB,IAAI,CAACI,YAAW;GACf,IAAI0B,KAAKC,IAAIH,EAAE,IAAI,KAAKE,KAAKC,IAAIF,EAAE,IAAI,GAAI;GAC3CxB,aAAayB,KAAKC,IAAIH,EAAE,IAAIE,KAAKC,IAAIF,EAAE;GACvCzB,aAAa;GACb,IAAIC,cAAcP,SAAUA,QAAQiB,QAAQZ,WAAW;EACxD;EACA,IAAI,CAACE,YAAa;EAClBC,QAAQ;EACR,IAAI0B,OAAO/B,aAAa2B;EACxB,IAAII,OAAO,GAAIA,OAAO;EACtB,IAAIA,OAAO,MAAiBA,OAAO,QAAkBA,OAAOjD,iBAAiB;EAC7EmB,gBAAgB8B;EAChBvB,eAAeuB,IAAI;CACpB;CAEA,MAAMC,eAAed,MAAK;EACzB,IAAI,CAAChB,UAAW;EAChBA,WAAW;EACXgB,EAAEK,cAAcU,wBAAwBf,EAAEO,SAAS;EACnD,IAAI,CAACrB,YAAa;EAElBQ,KADmBX,gBAAgB,GACpB;CAChB;CAEA,MAAMkC,sBAAsBjB,MAAK;EAChC,IAAIb,OAAM;GAAEa,EAAEkB,gBAAgB;GAAG;EAAO;EACxC,IAAIxC,OAAO,GAAE;GAAEsB,EAAEkB,gBAAgB;GAAGxB,KAAK,KAAK;GAAG;EAAO;CACzD;CAEA,MAAMyB,qBAAoBC,YAAUpB,MAAK;EACxCA,EAAEkB,gBAAgB;EAClBxB,KAAK,KAAK;EACV0B,OAAOC,UAAUrB,CAAC;CACnB;CAEA,aAAA;EAAA,MAAAsB,OAAA3D,MAAA4D,UAAA,IAAA;EAAA,MAAAC,OAAAF,KAAAG;EAAA,MAAAC,OAAAF,KAAAC;EAAA,MAAAE,OAAAH,KAAAC,WAAAG;EAAAC,OAAAH,YAYKrD,QAAQ;EAAAyD,QAAAJ,MAAA,mBADMxD,YAAY;EAAA4D,QAAAJ,MAAA,iBAAWT,kBAAkB;EAAAY,OAAAF,YAIvDvD,QAAQ2D,KAAIX,iBACZ;GAAA,MAAAE,OAAA7D,OAAA8D,UAAA,IAAA;GAAAM,OAAAP,YAQEF,OAAOY,KAAK;GAAAF,QAAAR,MAAA,mBANFrD,cAAc;GAAA6D,QAAAR,MAAA,iBAChBH,kBAAkBC,MAAM,CAAC;GAAAU,QAAAR,MAAA,gBAC3B,EAAEW,YAAYb,OAAOc,MAAM,EAAC;GAAAJ,QAAAR,MAAA,kBACzB5C,OAAO,IAAI,IAAI,EAAE;GAAA,OAAA4C;EAAA,CAK5B,CAAC;EAAAQ,QAAAH,MAAA,mBAZa3D,YAAY;EAAA8D,QAAAN,MAAA,mBAXjBzD,UAAU;EAAA+D,QAAAN,MAAA,yBAEJV,WAAW;EAAAgB,QAAAN,MAAA,uBACbzB,aAAa;EAAA+B,QAAAN,MAAA,uBACbhB,aAAa;EAAAsB,QAAAN,MAAA,qBACfV,WAAW;EAAAgB,QAAAN,MAAA,aACnBpC,WAAW;EAAA0C,QAAAR,MAAA,mBARFxD,YAAY;EAAA,OAAAwD;CAAA;AA8B9B"}
|
|
1
|
+
{"version":3,"file":"SwipeReveal.js","names":["css","createEffect","createSignal","_tmpl2","_template","_tmpl","ACTIONS_WIDTH","SWIPE_THRESHOLD","VELOCITY_THRESHOLD","RUBBER_BAND_LIMIT","wrapperClass","trackClass","actionsClass","actionBtnClass","contentClass","SwipeReveal","actions","children","onSwipeStart","onOpenChange","activeId","thisId","isOpen","trackEl","startX","startY","lastX","lastTime","baseOffset","currentOffset","velocity","dragging","axisLocked","horizontal","moved","setTrackRef","el","applyTransform","px","style","transform","setDragging","v","dataset","String","snap","toOpen","currentActive","undefined","onPointerDown","e","pointerType","button","clientX","clientY","performance","now","currentTarget","setPointerCapture","pointerId","onPointerMove","dx","dy","Math","abs","dt","next","exp","over","onPointerUp","releasePointerCapture","shouldOpen","handleContentClick","stopPropagation","handleActionClick","action","onClick","_el0","cloneNode","_el1","firstChild","_el2","_el3","nextSibling","_insert","_setProp","map","idx","label","background","color"],"sources":["../../src/components/SwipeReveal.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createEffect, createSignal } from '@plastic-js/plastic'\n\nconst ACTIONS_WIDTH = 160\nconst SWIPE_THRESHOLD = ACTIONS_WIDTH / 2\nconst VELOCITY_THRESHOLD = 0.5 // px/ms — flick assist threshold\nconst RUBBER_BAND_LIMIT = 50 // max rubber-band offset in px\n\nconst wrapperClass = css`\n\tposition: relative;\n\toverflow: hidden;\n\tborder-radius: 12px;\n\tuser-select: none;\n`\n\nconst trackClass = css`\n\tdisplay: flex;\n\talign-items: stretch;\n\twill-change: transform;\n\ttransition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1);\n\ttouch-action: pan-y;\n\t&[data-dragging=\"true\"] { transition: none; }\n`\n\nconst actionsClass = css`\n\tflex: 0 0 ${ACTIONS_WIDTH}px;\n\tdisplay: flex;\n`\n\nconst actionBtnClass = css`\n\tflex: 1;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder: none;\n\tcolor: #fff;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n\tfont-family: inherit;\n`\n\nconst contentClass = css`\n\tflex: 0 0 100%;\n`\n\nconst SwipeReveal = ({\n\tactions, children, onSwipeStart, onOpenChange, activeId, thisId,\n})=> {\n\tconst isOpen = createSignal(false)\n\n\tlet trackEl = null\n\tlet startX = 0\n\tlet startY = 0\n\tlet lastX = 0\n\tlet lastTime = 0\n\tlet baseOffset = 0\n\tlet currentOffset = 0\n\tlet velocity = 0\n\tlet dragging = false\n\tlet axisLocked = false\n\tlet horizontal = false\n\tlet moved = false\n\n\tconst setTrackRef = (el)=> { trackEl = el }\n\n\tconst applyTransform = (px)=> {\n\t\tif (trackEl){ trackEl.style.transform = `translateX(${px}px)` }\n\t}\n\n\tconst setDragging = (v)=> {\n\t\tif (trackEl){ trackEl.dataset.dragging = String(v) }\n\t}\n\n\tconst snap = (toOpen)=> {\n\t\tcurrentOffset = toOpen ? -ACTIONS_WIDTH : 0\n\t\tsetDragging(false)\n\t\tapplyTransform(currentOffset)\n\t\tonOpenChange?.(toOpen)\n\t\tisOpen(toOpen)\n\t}\n\n\t// only one card open at a time — close when another card's swipe activates\n\tcreateEffect(()=> {\n\t\tconst currentActive = typeof activeId === 'function' ? activeId() : activeId\n\t\tif (currentActive !== undefined && currentActive !== thisId && isOpen()){\n\t\t\tisOpen(false)\n\t\t\tcurrentOffset = 0\n\t\t\tsetDragging(false)\n\t\t\tapplyTransform(0)\n\t\t}\n\t})\n\n\tconst onPointerDown = (e)=> {\n\t\tif (e.pointerType === 'mouse' && e.button !== 0){ return }\n\t\tstartX = e.clientX\n\t\tstartY = e.clientY\n\t\tlastX = e.clientX\n\t\tlastTime = performance.now()\n\t\tbaseOffset = isOpen() ? -ACTIONS_WIDTH : 0\n\t\tvelocity = 0\n\t\tdragging = true\n\t\taxisLocked = false\n\t\thorizontal = false\n\t\tmoved = false\n\t\tonSwipeStart?.()\n\t\te.currentTarget.setPointerCapture?.(e.pointerId)\n\t}\n\n\tconst onPointerMove = (e)=> {\n\t\tif (!dragging){ return }\n\t\tconst dx = e.clientX - startX\n\t\tconst dy = e.clientY - startY\n\t\tif (!axisLocked){\n\t\t\tif (Math.abs(dx) < 6 && Math.abs(dy) < 6){ return }\n\t\t\thorizontal = Math.abs(dx) > Math.abs(dy)\n\t\t\taxisLocked = true\n\t\t\tif (horizontal){ setDragging(true) }\n\t\t}\n\t\tif (!horizontal){ return }\n\t\tmoved = true\n\n\t\t// track velocity (px/ms)\n\t\tconst now = performance.now()\n\t\tconst dt = now - lastTime\n\t\tif (dt > 0){\n\t\t\tvelocity = (e.clientX - lastX) / dt\n\t\t}\n\t\tlastX = e.clientX\n\t\tlastTime = now\n\n\t\tlet next = baseOffset + dx\n\t\tif (next > 0){\n\t\t\t// rubber-band overscroll on the right\n\t\t\tnext = RUBBER_BAND_LIMIT * (1 - Math.exp(-next / RUBBER_BAND_LIMIT))\n\t\t}\n\t\tif (next < -ACTIONS_WIDTH){\n\t\t\t// rubber-band overscroll on the left\n\t\t\tconst over = -(next + ACTIONS_WIDTH)\n\t\t\tnext = -ACTIONS_WIDTH - RUBBER_BAND_LIMIT * (1 - Math.exp(-over / RUBBER_BAND_LIMIT))\n\t\t}\n\t\tcurrentOffset = next\n\t\tapplyTransform(next)\n\t}\n\n\tconst onPointerUp = (e)=> {\n\t\tif (!dragging){ return }\n\t\tdragging = false\n\t\te.currentTarget.releasePointerCapture?.(e.pointerId)\n\t\tif (!horizontal){ return }\n\n\t\t// flick assist: fast swipe toward open/close direction\n\t\tif (Math.abs(velocity) > VELOCITY_THRESHOLD){\n\t\t\tsnap(velocity < 0)\n\t\t\treturn\n\t\t}\n\t\tconst shouldOpen = currentOffset < -SWIPE_THRESHOLD\n\t\tsnap(shouldOpen)\n\t}\n\n\tconst handleContentClick = (e)=> {\n\t\tif (moved){ e.stopPropagation(); return }\n\t\tif (isOpen()){ e.stopPropagation(); snap(false); return }\n\t}\n\n\tconst handleActionClick = action=> (e)=> {\n\t\te.stopPropagation()\n\t\tsnap(false)\n\t\taction.onClick?.(e)\n\t}\n\n\treturn (\n\t\t<div className={wrapperClass}>\n\t\t\t<div\n\t\t\t\tclassName={trackClass}\n\t\t\t\tdata-dragging='false'\n\t\t\t\tonPointerCancel={onPointerUp}\n\t\t\t\tonPointerDown={onPointerDown}\n\t\t\t\tonPointerMove={onPointerMove}\n\t\t\t\tonPointerUp={onPointerUp}\n\t\t\t\tref={setTrackRef}\n\t\t\t>\n\t\t\t\t<div className={contentClass} onClick={handleContentClick}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t\t<div className={actionsClass}>\n\t\t\t\t\t{actions.map((action, idx)=> (\n\t\t\t\t\t\t// prevent tab focus when actions are hidden off-screen\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tclassName={actionBtnClass}\n\t\t\t\t\t\t\tkey={action.label ?? idx}\n\t\t\t\t\t\t\tonClick={handleActionClick(action)}\n\t\t\t\t\t\t\tstyle={{ background: action.color }}\n\t\t\t\t\t\t\ttabIndex={isOpen() ? 0 : -1}\n\t\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{action.label}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nexport default SwipeReveal\n"],"mappings":"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"}
|