@plastic-js/tsumiki 0.1.14 → 0.1.15
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 +11 -0
- package/dist/components/FilterableSelectMobile.js +3 -0
- package/dist/components/FilterableSelectMobile.js.map +1 -1
- package/dist/components/SelectMobile/index.js +3 -2
- 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,17 @@ 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>`.
|
|
69
|
+
> This is a workaround for a **Chrome iOS (WebKit) bug**: tapping a native `<button>` inside a scrollable container
|
|
70
|
+
> with `-webkit-overflow-scrolling: touch` permanently pins `activeElement` to the button. After the trigger opens
|
|
71
|
+
> the sheet, any subsequent `focus()` call on the filter `<input>` inside the list is silently ignored.
|
|
72
|
+
> A `<div role="button">` is semantically equivalent for accessibility but avoids this WebKit focus-lock behaviour.
|
|
73
|
+
>
|
|
74
|
+
> Typically a native `<button>` would be preferred for keyboard tab navigation (`tabIndex` works natively).
|
|
75
|
+
> On mobile, however, keyboard tab navigation is irrelevant — the sheet is operated via touch, and the Escape key
|
|
76
|
+
> for closing is handled by the `Dialog`-like overlay, not by tab order. The `tabIndex={0}` on the `<div>` preserves
|
|
77
|
+
> keyboard discoverability for assistive technology while working around the iOS focus trap.
|
|
78
|
+
|
|
68
79
|
**SelectMobile.Content props:**
|
|
69
80
|
|
|
70
81
|
| 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// iOS WebKit workaround: ensure focus moves to input even when\n\t\t\t\t\t\t// a previous button element holds focus (Chrome iOS bug).\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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"}
|
|
@@ -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}`;
|
|
@@ -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> to work around a\n// Chrome iOS (WebKit) bug where tapping a <button> inside a scrollable container\n// with -webkit-overflow-scrolling:touch permanently pins activeElement to the\n// button. After the trigger opens the sheet, any subsequent focus() call on the\n// search <input> inside the list is silently ignored — the browser refuses to\n// release focus from the button. A <div role=\"button\"> is semantically equivalent\n// for accessibility but doesn't trigger this WebKit focus-lock behaviour.\n//\n// The original <button> was chosen for keyboard tab accessibility (tabIndex\n// works natively on <button>). On mobile, however, keyboard navigation is\n// irrelevant — the sheet is operated via touch, and the Escape key for closing\n// is handled by the Dialog overlay, not by tab order. The <div role=\"button\">\n// with tabIndex={0} preserves keyboard discoverability for assistive technology\n// while avoiding the iOS focus trap.\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)\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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"}
|
|
@@ -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":"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"}
|
|
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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"}
|