@adea-ai/ui 0.146.11 → 0.147.1
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/dist/components/composites/update-dialog/channel-control.d.ts +4 -2
- package/dist/components/composites/update-dialog/channel-control.d.ts.map +1 -1
- package/dist/components/composites/update-dialog/channel-control.js +8 -3
- package/dist/components/composites/update-dialog/channel-control.js.map +1 -1
- package/dist/components/layout/side-rail/side-rail.d.ts.map +1 -1
- package/dist/components/layout/side-rail/side-rail.js +4 -2
- package/dist/components/layout/side-rail/side-rail.js.map +1 -1
- package/dist/r/src/components/composites/update-dialog/channel-control.tsx +8 -3
- package/dist/r/src/components/layout/side-rail/side-rail.tsx +10 -8
- package/package.json +1 -1
- package/src/components/composites/update-dialog/channel-control.tsx +8 -3
- package/src/components/layout/side-rail/side-rail.tsx +10 -8
|
@@ -10,6 +10,8 @@ export type UpdateChannelControlProps = {
|
|
|
10
10
|
persist: (value: UpdateChannel) => Promise<UpdateChannel>;
|
|
11
11
|
/** Disable beyond the dialog's own working state, e.g. a host save in flight. */
|
|
12
12
|
disabled?: Accessor<boolean>;
|
|
13
|
+
/** Per-channel option labels, when the defaults don't fit the app. Values remain unchanged. */
|
|
14
|
+
labels?: Partial<Record<UpdateChannel, string>>;
|
|
13
15
|
/** Per-channel row descriptions, when the defaults don't fit the app. */
|
|
14
16
|
descriptions?: Partial<Record<UpdateChannel, string>>;
|
|
15
17
|
/**
|
|
@@ -22,8 +24,8 @@ export type UpdateChannelControlProps = {
|
|
|
22
24
|
/**
|
|
23
25
|
* The updater dialog's release-channel row: one setting, a select trailing.
|
|
24
26
|
* Every desktop application that ships channels presents the same three of
|
|
25
|
-
* them with
|
|
26
|
-
* redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
27
|
+
* them with consistent behavior, which is why the row lives here rather than
|
|
28
|
+
* being redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
27
29
|
* channel switch re-asks the feed and the offer never outlives its channel.
|
|
28
30
|
*/
|
|
29
31
|
export declare function UpdateChannelControl(props: UpdateChannelControlProps): import("solid-js").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/update-dialog/channel-control.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAErF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE5D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,aAAa,GAAG,KAAK,CAAA;AAc5D,MAAM,MAAM,yBAAyB,GAAG;IACtC,wEAAwE;IACxE,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,kCAAkC;IAClC,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IAClC,0EAA0E;IAC1E,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;IACzD,iFAAiF;IACjF,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC5B,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAA;IACrD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"channel-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/update-dialog/channel-control.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+C,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAErF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE5D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,aAAa,GAAG,KAAK,CAAA;AAc5D,MAAM,MAAM,yBAAyB,GAAG;IACtC,wEAAwE;IACxE,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,kCAAkC;IAClC,IAAI,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IAClC,0EAA0E;IAC1E,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;IACzD,iFAAiF;IACjF,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC5B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAA;IAC/C,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAA;IACrD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,kCAoFpE"}
|
|
@@ -27,8 +27,8 @@ var CHANNEL_DESCRIPTIONS = {
|
|
|
27
27
|
/**
|
|
28
28
|
* The updater dialog's release-channel row: one setting, a select trailing.
|
|
29
29
|
* Every desktop application that ships channels presents the same three of
|
|
30
|
-
* them with
|
|
31
|
-
* redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
30
|
+
* them with consistent behavior, which is why the row lives here rather than
|
|
31
|
+
* being redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
32
32
|
* channel switch re-asks the feed and the offer never outlives its channel.
|
|
33
33
|
*/
|
|
34
34
|
function UpdateChannelControl(props) {
|
|
@@ -95,7 +95,12 @@ function UpdateChannelControl(props) {
|
|
|
95
95
|
get value() {
|
|
96
96
|
return channel();
|
|
97
97
|
},
|
|
98
|
-
options
|
|
98
|
+
get options() {
|
|
99
|
+
return CHANNEL_OPTIONS.map((option) => ({
|
|
100
|
+
...option,
|
|
101
|
+
label: props.labels?.[option.value] ?? option.label
|
|
102
|
+
}));
|
|
103
|
+
},
|
|
99
104
|
onChange: (event) => void save(event.currentTarget.value)
|
|
100
105
|
});
|
|
101
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-control.js","names":["SettingsRow","NativeSelect","createEffect","createSignal","onCleanup","Show","Accessor","ChannelControlActions","UpdateChannel","CHANNEL_OPTIONS","ReadonlyArray","value","label","CHANNEL_DESCRIPTIONS","Record","stable","dev","UpdateChannelControlProps","controls","read","Promise","persist","disabled","
|
|
1
|
+
{"version":3,"file":"channel-control.js","names":["SettingsRow","NativeSelect","createEffect","createSignal","onCleanup","Show","Accessor","ChannelControlActions","UpdateChannel","CHANNEL_OPTIONS","ReadonlyArray","value","label","CHANNEL_DESCRIPTIONS","Record","stable","dev","UpdateChannelControlProps","controls","read","Promise","persist","disabled","labels","Partial","descriptions","reloadOn","UpdateChannelControl","props","channel","setChannel","loaded","setLoaded","saving","setSaving","error","setError","active","then","catch","finally","save","next","previous","persisted","recheck","saved","caught","Error","message","_el$","_tmpl$","_$insert","_$createComponent","description","children","options","map","option","onChange","event","currentTarget","when","_el$2","_tmpl$2","_$createComponent"],"sources":["../../../../src/components/composites/update-dialog/channel-control.tsx"],"sourcesContent":["import { SettingsRow } from '../settings'\nimport { NativeSelect } from '../../ui/native-select'\nimport { createEffect, createSignal, onCleanup, Show, type Accessor } from 'solid-js'\n\nimport type { ChannelControlActions } from './update-dialog'\n\nexport type UpdateChannel = 'stable' | 'pre-release' | 'dev'\n\nconst CHANNEL_OPTIONS: ReadonlyArray<{ value: UpdateChannel; label: string }> = [\n { value: 'stable', label: 'Stable' },\n { value: 'pre-release', label: 'Pre-release' },\n { value: 'dev', label: 'Dev' },\n]\n\nconst CHANNEL_DESCRIPTIONS: Record<UpdateChannel, string> = {\n stable: 'Tested releases after about four days in pre-release.',\n 'pre-release': 'Daily pre-release builds arrive early, with rough edges included.',\n dev: 'Follows every dev build from main. Intended for development machines.',\n}\n\nexport type UpdateChannelControlProps = {\n /** The dialog's channel actions; every save flows through `recheck`. */\n controls: ChannelControlActions\n /** Read the persisted channel. */\n read: () => Promise<UpdateChannel>\n /** Persist a selection; resolves with the channel that actually stuck. */\n persist: (value: UpdateChannel) => Promise<UpdateChannel>\n /** Disable beyond the dialog's own working state, e.g. a host save in flight. */\n disabled?: Accessor<boolean>\n /** Per-channel option labels, when the defaults don't fit the app. Values remain unchanged. */\n labels?: Partial<Record<UpdateChannel, string>>\n /** Per-channel row descriptions, when the defaults don't fit the app. */\n descriptions?: Partial<Record<UpdateChannel, string>>\n /**\n * Re-read the persisted channel whenever this value changes. Supply it when\n * the channel can move while the dialog is closed — a service that gets torn\n * down, or a CLI writing the same setting — and hand it the dialog's `open`.\n */\n reloadOn?: Accessor<unknown>\n}\n\n/**\n * The updater dialog's release-channel row: one setting, a select trailing.\n * Every desktop application that ships channels presents the same three of\n * them with consistent behavior, which is why the row lives here rather than\n * being redrawn per app. A save always flows through the dialog's `recheck`, so a\n * channel switch re-asks the feed and the offer never outlives its channel.\n */\nexport function UpdateChannelControl(props: UpdateChannelControlProps) {\n const [channel, setChannel] = createSignal<UpdateChannel>('stable')\n const [loaded, setLoaded] = createSignal(false)\n const [saving, setSaving] = createSignal(false)\n const [error, setError] = createSignal<string | null>(null)\n\n createEffect(() => {\n props.reloadOn?.()\n let active = true\n onCleanup(() => {\n active = false\n })\n void props\n .read()\n .then((value) => {\n if (active) setChannel(value)\n })\n .catch(() => {\n if (active) setError('The current update channel could not be read.')\n })\n .finally(() => {\n if (active) setLoaded(true)\n })\n })\n\n const save = async (value: string) => {\n const next = value as UpdateChannel\n if (!loaded() || saving() || props.controls.disabled() || next === channel()) return\n const previous = channel()\n let persisted = false\n setChannel(next)\n setSaving(true)\n setError(null)\n\n try {\n await props.controls.recheck(async () => {\n try {\n const saved = await props.persist(next)\n setChannel(saved)\n persisted = true\n } catch (caught) {\n setChannel(previous)\n setError(\n caught instanceof Error ? caught.message : 'The update channel could not be saved.'\n )\n throw caught\n }\n })\n } catch (caught) {\n // The shared dialog renders the recheck failure. Roll back only if the\n // channel write itself failed; a failed feed check keeps the saved choice.\n if (!persisted) {\n setChannel(previous)\n setError(\n caught instanceof Error ? caught.message : 'The update channel could not be saved.'\n )\n }\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <div class=\"flex flex-col gap-2\">\n <SettingsRow\n label=\"Update channel\"\n description={props.descriptions?.[channel()] ?? CHANNEL_DESCRIPTIONS[channel()]}\n >\n <NativeSelect\n aria-label=\"Update channel\"\n disabled={\n !loaded() || saving() || props.controls.disabled() || (props.disabled?.() ?? false)\n }\n value={channel()}\n options={CHANNEL_OPTIONS.map((option) => ({\n ...option,\n label: props.labels?.[option.value] ?? option.label,\n }))}\n onChange={(event) => void save(event.currentTarget.value)}\n />\n </SettingsRow>\n <Show when={error()}>{(message) => <p role=\"alert\">{message()}</p>}</Show>\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"side-rail.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/side-rail/side-rail.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAOnE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAC5E,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CACF,CAAA;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,eAmCjF;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY1D;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY3D;AAED,kDAAkD;AAClD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY1D;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,eAahF;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAiBnB,CAAA;AAUX,eAAO,MAAM,sBAAsB;IACjC,MAAM;IACN,IAAI;CACL,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,gBAAgB,CAC9E,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACnB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CACF,CAAA;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"side-rail.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/side-rail/side-rail.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAOnE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAC5E,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CACF,CAAA;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,eAmCjF;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY1D;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY3D;AAED,kDAAkD;AAClD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eAY1D;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,eAahF;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAiBnB,CAAA;AAUX,eAAO,MAAM,sBAAsB;IACjC,MAAM;IACN,IAAI;CACL,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,gBAAgB,CAC9E,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACnB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CACF,CAAA;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,eA6HvF;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG;IAC9C,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,eA8EF"}
|
|
@@ -220,6 +220,7 @@ function SideRailItem(props) {
|
|
|
220
220
|
get when() {
|
|
221
221
|
return tip();
|
|
222
222
|
},
|
|
223
|
+
keyed: true,
|
|
223
224
|
children: (position) => createComponent(Portal, { get children() {
|
|
224
225
|
var _el$1 = _tmpl$10(), _el$10 = _el$1.firstChild;
|
|
225
226
|
insert(_el$10, () => local.children);
|
|
@@ -235,7 +236,7 @@ function SideRailItem(props) {
|
|
|
235
236
|
}
|
|
236
237
|
}), null);
|
|
237
238
|
effect((_p$) => {
|
|
238
|
-
var _v$ = cn(tooltipTip, "pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap"), _v$2 = `${position
|
|
239
|
+
var _v$ = cn(tooltipTip, "pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap"), _v$2 = `${position.top}px`, _v$3 = `${position.left}px`, _v$4 = `${position.height}px`, _v$5 = cn("flex size-5 shrink-0 items-center justify-center [&_svg]:size-5", { "text-primary": local.active });
|
|
239
240
|
_v$ !== _p$.e && className(_el$1, _p$.e = _v$);
|
|
240
241
|
_v$2 !== _p$.t && setStyleProperty(_el$1, "top", _p$.t = _v$2);
|
|
241
242
|
_v$3 !== _p$.a && setStyleProperty(_el$1, "left", _p$.a = _v$3);
|
|
@@ -310,12 +311,13 @@ function SideRailButton(props) {
|
|
|
310
311
|
get when() {
|
|
311
312
|
return tip();
|
|
312
313
|
},
|
|
314
|
+
keyed: true,
|
|
313
315
|
children: (position) => createComponent(Portal, { get children() {
|
|
314
316
|
var _el$16 = _tmpl$12(), _el$17 = _el$16.firstChild;
|
|
315
317
|
insert(_el$17, () => local.children);
|
|
316
318
|
insert(_el$16, () => local.label, null);
|
|
317
319
|
effect((_p$) => {
|
|
318
|
-
var _v$6 = cn(tooltipTip, "pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap"), _v$7 = `${position
|
|
320
|
+
var _v$6 = cn(tooltipTip, "pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap"), _v$7 = `${position.top}px`, _v$8 = `${position.left}px`, _v$9 = `${position.height}px`;
|
|
319
321
|
_v$6 !== _p$.e && className(_el$16, _p$.e = _v$6);
|
|
320
322
|
_v$7 !== _p$.t && setStyleProperty(_el$16, "top", _p$.t = _v$7);
|
|
321
323
|
_v$8 !== _p$.a && setStyleProperty(_el$16, "left", _p$.a = _v$8);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"side-rail.js","names":["Polymorphic","PolymorphicProps","ComponentProps","JSX","ValidComponent","Show","createMemo","createSignal","splitProps","Portal","tooltipTip","cn","SideRailContext","createSideRailValue","SideRailProps","T","class","collapsed","SideRail","props","local","rest","value","_$createComponent","Provider","children","_$mergeProps","as","aria-label","data-collapsed","SideRailHeader","_el$","_tmpl$","_$spread","SideRailContent","_el$2","_tmpl$2","SideRailFooter","_el$3","_tmpl$3","SideRailSection","label","_el$4","_tmpl$5","_$insert","when","_el$5","_tmpl$4","sideRailItemClass","join","sideRailItemStateClass","active","idle","SideRailItemProps","badge","Element","trailing","shortcut","keyshortcuts","SideRailItem","row","setRow","HTMLElement","tip","setTip","top","left","height","closest","getAttribute","showTip","element","rect","getBoundingClientRect","right","hideTip","ref","aria-current","undefined","aria-keyshortcuts","data-active","onPointerEnter","onPointerLeave","onFocus","onBlur","Record","_el$6","_tmpl$6","_el$7","_tmpl$7","_el$8","_tmpl$8","_$memo","_el$9","_tmpl$9","_el$0","_tmpl$0","position","_el$1","_tmpl$10","_el$10","firstChild","_el$11","_tmpl$1","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","e","_$className","t","_$setStyleProperty","a","o","i","SideRailButton","Omit","_el$12","_tmpl$11","_el$13","_el$14","nextSibling","addEventListener","_$use","_el$15","_el$16","_tmpl$12","_el$17","_v$6","_v$7","_v$8","_v$9","_$createComponent","_$mergeProps","_$memo","_$className","_$setStyleProperty"],"sources":["../../../../src/components/layout/side-rail/side-rail.tsx"],"sourcesContent":["import { Polymorphic, type PolymorphicProps } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, createMemo, createSignal, splitProps } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport { tooltipTip } from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { SideRailContext, createSideRailValue } from './side-rail-context'\n\n/**\n * SideRail.\n *\n * The narrow, persistent column of top-level destinations at the window's leading\n * edge: the app mark, the primary sections, and a footer for account and settings.\n * It is the one piece of chrome that is always on screen, which is why it is a\n * component rather than something each view arranges.\n *\n * Two forms, one component. Collapsed it is an icon column; expanded it carries\n * labels. Both widths come from `--rail-width` (56px) and `--rail-width-expanded`\n * (236px), so an app cannot pick its own and end up a few pixels out of step with\n * the app beside it.\n *\n * The rail does not own its collapsed state; the app does. That state has to\n * survive a reload and usually lives with the rest of the window preferences, and\n * a rail that kept it privately could not be restored.\n */\nexport type SideRailProps<T extends ValidComponent = 'nav'> = PolymorphicProps<\n T,\n {\n class?: string\n collapsed?: boolean\n 'aria-label'?: string\n }\n>\n\nexport function SideRail<T extends ValidComponent = 'nav'>(props: SideRailProps<T>) {\n const [local, rest] = splitProps(props as SideRailProps, [\n 'class',\n 'collapsed',\n 'aria-label',\n 'children',\n ])\n\n const collapsed = () => local.collapsed ?? false\n const value = createSideRailValue(\n collapsed,\n createMemo(() => (collapsed() ? 'var(--rail-width)' : 'var(--rail-width-expanded)'))\n )\n\n return (\n <SideRailContext.Provider value={value}>\n <Polymorphic\n as=\"nav\"\n aria-label={local['aria-label'] ?? 'Primary'}\n /* Rendered in both states, with a real value, so the descendant selectors\n below can key on true *and* false — an absent attribute would leave the\n expanded form matching neither. */\n data-collapsed={collapsed() ? 'true' : 'false'}\n class={cn(\n 'group/rail bg-sidebar text-sidebar-foreground flex h-full shrink-0 flex-col border-e border-sidebar-border',\n 'transition-[width] duration-150 ease-out',\n { 'w-rail': collapsed(), 'w-rail-expanded': !collapsed() },\n local.class\n )}\n {...(rest as ComponentProps<'nav'>)}\n >\n {local.children}\n </Polymorphic>\n </SideRailContext.Provider>\n )\n}\n\n/** The header slot: the app mark, and the product name when there is room. */\nexport function SideRailHeader(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-header\"\n class={cn(\n 'h-topbar flex shrink-0 items-center gap-2.5 px-3 group-data-[collapsed=true]/rail:justify-center group-data-[collapsed=true]/rail:px-0',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** The scrolling middle. Keeps the header and the footer pinned. */\nexport function SideRailContent(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-content\"\n class={cn(\n 'flex min-h-0 flex-1 flex-col gap-0.5 overflow-x-hidden overflow-y-auto px-2 py-2',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** The pinned footer: account, settings, help. */\nexport function SideRailFooter(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-footer\"\n class={cn(\n 'flex shrink-0 flex-col gap-0.5 border-t border-sidebar-border px-2 py-2',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A titled group of rail destinations. The title hides when collapsed. */\nexport function SideRailSection(props: ComponentProps<'div'> & { label?: string }) {\n const [local, rest] = splitProps(props, ['class', 'label', 'children'])\n\n return (\n <div data-slot=\"side-rail-section\" class={cn('flex flex-col gap-0.5', local.class)} {...rest}>\n <Show when={local.label}>\n <div class=\"text-sidebar-muted-foreground px-2 pt-2 pb-1 text-2xs font-medium tracking-wide uppercase group-data-[collapsed=true]/rail:hidden\">\n {local.label}\n </div>\n </Show>\n {local.children}\n </div>\n )\n}\n\n/**\n * The classes a rail row uses. Exported so a caller's own element — a router link,\n * a custom button — can match the rail exactly instead of approximating it.\n */\nexport const sideRailItemClass = [\n 'group/rail-item flex h-rail-item min-w-0 w-full items-center gap-2.5 rounded-md px-3 text-sm font-medium',\n 'group-data-[collapsed=true]/rail:justify-center group-data-[collapsed=true]/rail:px-0',\n 'transition-[color,background-color,transform] ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n /*\n * The donor's row scales up slightly under the pointer and down under a press.\n * It is a CSS transform rather than a motion-library gesture because the two are\n * the same thing here and the transform costs nothing at runtime: no wrapper\n * element, no listener, and it works on whatever element a caller renders the row\n * as — an anchor, a button, a router's own link.\n *\n * The collapsed rail opts out: a 1.02 scale on a 56px column pushes the row past\n * the rail's own edge, which reads as a glitch rather than as feedback.\n */\n 'hover:scale-[1.02] active:scale-[0.97] group-data-[collapsed=true]/rail:hover:scale-100 group-data-[collapsed=true]/rail:active:scale-[0.98]',\n '[&_svg]:size-5 [&_svg]:shrink-0',\n].join(' ')\n\n/*\n * The rail's states are accent-driven: the icon carries `--primary` on hover and\n * on the active destination, and both states draw the accent's own tint rather\n * than a neutral fill, so the rail reads as the app's accent chroma instead of a\n * grey column. The active label stays on `sidebar-foreground` because the accent\n * presets guarantee their 3:1 interaction minimum against the surface, not the\n * 4.5:1 small text owes; the icon is a graphic and rides the accent.\n */\nexport const sideRailItemStateClass = {\n active: 'bg-primary-subtle text-sidebar-foreground [&_svg]:text-primary',\n idle: 'text-sidebar-muted-foreground hover:bg-primary-subtle/60 hover:text-primary',\n}\n\n/**\n * A rail destination.\n *\n * ## The tooltip is the rail's hover affordance, not a generic bubble\n *\n * Collapsed, the row has no text, so the label has to come from somewhere. This\n * ports the donor's treatment rather than using a standard tooltip, because the\n * details are what make it read as part of the rail:\n *\n * - It is **flush with the row**: positioned at the row's own top and given the\n * row's own height, so it continues the row outward instead of floating near\n * it. A centred bubble with an arrow reads as a separate object.\n * - It **repeats the icon**, which anchors it to the row it belongs to.\n * - It carries the **keyboard chord**, which is the one piece of information a\n * collapsed rail otherwise cannot show.\n * - It opens on **hover and on focus**, so a keyboard user gets the same label a\n * pointer user does.\n * - It is `pointer-events-none` and `aria-hidden`: the row already carries the\n * name (as a visually hidden span when collapsed), so this is decoration and\n * must never be the accessible name.\n *\n * ## The chord on the row\n *\n * Expanded, the row shows its chord on hover and on focus — and the chord is\n * declared once to assistive technology through `aria-keyshortcuts` rather than\n * being read out as glyphs. The visible badge is `aria-hidden` for that reason.\n */\nexport type SideRailItemProps<T extends ValidComponent = 'a'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the item as the current destination. */\n active?: boolean\n /**\n * The item's accessible name. Required, and always in the accessibility tree:\n * collapsed it moves into the tooltip and a visually hidden span rather than\n * being deleted.\n */\n label: string\n /**\n * A count or a dot. Expanded, it trails the label at the row's end; collapsed,\n * it moves onto the icon's corner, so the rail never loses it.\n */\n badge?: JSX.Element\n /** An indicator pinned to the trailing edge in the expanded form. */\n trailing?: JSX.Element\n /** The chord as it should be drawn, e.g. `⌘1`. Shown on hover and focus. */\n shortcut?: string\n /**\n * The same chord in the ARIA grammar, e.g. `Meta+1`. Declared to assistive\n * technology instead of the display glyphs, which are not a keyboard shortcut\n * a screen reader can parse. Supply it whenever `shortcut` is drawn.\n */\n keyshortcuts?: string\n }\n>\n\nexport function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItemProps<T>) {\n const [local, rest] = splitProps(props as SideRailItemProps, [\n 'as',\n 'class',\n 'active',\n 'label',\n 'badge',\n 'trailing',\n 'shortcut',\n 'keyshortcuts',\n 'children',\n ])\n\n const [row, setRow] = createSignal<HTMLElement>()\n const [tip, setTip] = createSignal<{ top: number; left: number; height: number } | null>(null)\n\n const collapsed = () =>\n row()?.closest('[data-collapsed]')?.getAttribute('data-collapsed') === 'true'\n\n const showTip = () => {\n const element = row()\n if (!element || !collapsed()) return\n const rect = element.getBoundingClientRect()\n setTip({ top: rect.top, left: rect.right + 8, height: rect.height })\n }\n\n const hideTip = () => setTip(null)\n\n return (\n <>\n <Polymorphic\n as={local.as ?? 'a'}\n ref={setRow}\n aria-current={local.active ? 'page' : undefined}\n aria-keyshortcuts={local.keyshortcuts}\n data-active={local.active ? '' : undefined}\n class={cn(\n sideRailItemClass,\n 'relative',\n local.active ? sideRailItemStateClass.active : sideRailItemStateClass.idle,\n local.class\n )}\n onPointerEnter={showTip}\n onPointerLeave={hideTip}\n onFocus={showTip}\n onBlur={hideTip}\n {...(rest as Record<string, unknown>)}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n\n <span class=\"min-w-0 flex-1 truncate text-start group-data-[collapsed=true]/rail:sr-only\">\n {local.label}\n </span>\n\n {/*\n * One element, two placements, because the badge is caller content and a DOM\n * node cannot be in two places. Expanded, it is a trailing count in the row's\n * flow, after the label — over the icon it would cover the glyph the row is\n * recognised by. Collapsed, there is no label to trail, so it leaves the flow\n * and pins to the icon's top-end corner: anchored to the row's centre (where\n * the centred icon sits) and pushed out by 14px, the icon's half-width plus\n * the 4px overhang, so a wider count grows back over the icon rather than past\n * the rail's edge.\n */}\n <Show when={local.badge}>\n <span\n data-slot=\"side-rail-badge\"\n class=\"flex shrink-0 items-center justify-center group-data-[collapsed=true]/rail:absolute group-data-[collapsed=true]/rail:end-1/2 group-data-[collapsed=true]/rail:top-1/2 group-data-[collapsed=true]/rail:-me-3.5 group-data-[collapsed=true]/rail:-mt-3.5\"\n >\n {local.badge}\n </span>\n </Show>\n\n <Show when={local.shortcut && local.trailing === undefined}>\n <span\n aria-hidden=\"true\"\n class=\"text-sidebar-muted-foreground shrink-0 font-code text-code leading-none opacity-0 transition-opacity group-hover/rail-item:opacity-100 group-focus-visible/rail-item:opacity-100 group-data-[collapsed=true]/rail:hidden\"\n >\n {local.shortcut}\n </span>\n </Show>\n\n <Show when={local.trailing}>\n <span class=\"ms-auto shrink-0\">{local.trailing}</span>\n </Show>\n </Polymorphic>\n\n <Show when={tip()}>\n {(position) => (\n <Portal>\n <div\n aria-hidden=\"true\"\n data-slot=\"side-rail-tip\"\n class={cn(\n tooltipTip,\n 'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'\n )}\n style={{\n top: `${position().top}px`,\n left: `${position().left}px`,\n height: `${position().height}px`,\n }}\n >\n <span\n class={cn('flex size-5 shrink-0 items-center justify-center [&_svg]:size-5', {\n 'text-primary': local.active,\n })}\n >\n {local.children}\n </span>\n {local.label}\n <Show when={local.shortcut}>\n <span class=\"text-muted-foreground shrink-0 font-code text-code leading-none\">\n {local.shortcut}\n </span>\n </Show>\n </div>\n </Portal>\n )}\n </Show>\n </>\n )\n}\n\n/** A non-navigating rail control: a collapse toggle, a \"new\" action. */\nexport function SideRailButton(\n props: Omit<ComponentProps<'button'>, 'type'> & {\n label: string\n shortcut?: string\n active?: boolean\n }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'shortcut', 'children', 'active'])\n const [row, setRow] = createSignal<HTMLElement>()\n const [tip, setTip] = createSignal<{ top: number; left: number; height: number } | null>(null)\n\n const collapsed = () =>\n row()?.closest('[data-collapsed]')?.getAttribute('data-collapsed') === 'true'\n\n const showTip = () => {\n const element = row()\n if (!element || !collapsed()) return\n const rect = element.getBoundingClientRect()\n setTip({ top: rect.top, left: rect.right + 8, height: rect.height })\n }\n\n return (\n <>\n <button\n type=\"button\"\n ref={setRow}\n aria-label={local.label}\n data-active={local.active ? 'true' : undefined}\n onPointerEnter={showTip}\n onPointerLeave={() => setTip(null)}\n onFocus={showTip}\n onBlur={() => setTip(null)}\n class={cn(\n sideRailItemClass,\n local.active ? sideRailItemStateClass.active : sideRailItemStateClass.idle,\n 'disabled:pointer-events-none disabled:opacity-50',\n local.class\n )}\n {...rest}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n <span class=\"min-w-0 flex-1 truncate text-start group-data-[collapsed=true]/rail:sr-only\">\n {local.label}\n </span>\n <Show when={local.shortcut}>\n <span\n aria-hidden=\"true\"\n class=\"text-sidebar-muted-foreground shrink-0 font-code text-code leading-none opacity-0 transition-opacity group-hover/rail-item:opacity-100 group-focus-visible/rail-item:opacity-100 group-data-[collapsed=true]/rail:hidden\"\n >\n {local.shortcut}\n </span>\n </Show>\n </button>\n\n <Show when={tip()}>\n {(position) => (\n <Portal>\n <div\n aria-hidden=\"true\"\n data-slot=\"side-rail-tip\"\n class={cn(\n tooltipTip,\n 'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'\n )}\n style={{\n top: `${position().top}px`,\n left: `${position().left}px`,\n height: `${position().height}px`,\n }}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n {local.label}\n </div>\n </Portal>\n )}\n </Show>\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,SAAgBkB,SAA2CC,OAAyB;CAClF,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAwB;EACvD;EACA;EACA;EACA;CAAU,CACX;CAED,MAAMF,kBAAkBG,MAAMH,aAAa;CAC3C,MAAMK,QAAQT,oBACZI,WACAX,iBAAkBW,UAAU,IAAI,sBAAsB,4BAA6B,CACrF;CAEA,OAAAM,gBACGX,gBAAgBY,UAAQ;EAAQF;EAAK,IAAAG,WAAA;GAAA,OAAAF,gBACnCvB,aAAW0B,WAAA;IACVC,IAAE;IAAA,KAAA,gBAAA;KAAA,OACUP,MAAM,iBAAiB;IAAS;IAAA,KAAA,oBAAA;KAAA,OAI5BH,UAAU,IAAI,SAAS;IAAO;IAAA,KAAA,WAAA;KAAA,OACvCN,GACL,8GACA,4CACA;MAAE,UAAUM,UAAU;MAAG,mBAAmB,CAACA,UAAU;KAAE,GACzDG,MAAMJ,KACR;IAAC;GAAA,GACIK,MAA6B,EAAA,IAAAI,WAAA;IAAA,OAEjCL,MAAMK;GAAQ,EAAA,CAAA,CAAA;EAAA;CAAA,CAAA;AAIvB;;AAGA,SAAgBK,eAAeX,OAA8B;CAC3D,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAO,CAAC,OAAO,CAAC;CACjD,cAAA;EAAA,IAAAY,OAAAC,OAAA;EAAAC,OAAAF,MAAAL,WAAA,EAAA,KAAA,WAAA;GAAA,OAGWf,GACL,0IACAS,MAAMJ,KACR;EAAC,EAAA,GACGK,IAAI,GAAA,OAAA,KAAA;EAAA,OAAAU;CAAA,EAAA,CAAA;AAGd;;AAGA,SAAgBG,gBAAgBf,OAA8B;CAC5D,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAO,CAAC,OAAO,CAAC;CACjD,cAAA;EAAA,IAAAgB,QAAAC,QAAA;EAAAH,OAAAE,OAAAT,WAAA,EAAA,KAAA,WAAA;GAAA,OAGWf,GACL,oFACAS,MAAMJ,KACR;EAAC,EAAA,GACGK,IAAI,GAAA,OAAA,KAAA;EAAA,OAAAc;CAAA,EAAA,CAAA;AAGd;;AAGA,SAAgBE,eAAelB,OAA8B;CAC3D,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAO,CAAC,OAAO,CAAC;CACjD,cAAA;EAAA,IAAAmB,QAAAC,QAAA;EAAAN,OAAAK,OAAAZ,WAAA,EAAA,KAAA,WAAA;GAAA,OAGWf,GACL,2EACAS,MAAMJ,KACR;EAAC,EAAA,GACGK,IAAI,GAAA,OAAA,KAAA;EAAA,OAAAiB;CAAA,EAAA,CAAA;AAGd;;AAGA,SAAgBE,gBAAgBrB,OAAmD;CACjF,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAO;EAAC;EAAS;EAAS;CAAU,CAAC;CAEtE,cAAA;EAAA,IAAAuB,QAAAC,QAAA;EAAAV,OAAAS,OAAAhB,WAAA,EAAA,KAAA,WAAA;GAAA,OAC4Cf,GAAG,yBAAyBS,MAAMJ,KAAK;EAAC,EAAA,GAAMK,IAAI,GAAA,OAAA,IAAA;EAAAuB,OAAAF,OAAAnB,gBACzFlB,MAAI;GAAA,IAACwC,OAAI;IAAA,OAAEzB,MAAMqB;GAAK;GAAA,IAAAhB,WAAA;IAAA,IAAAqB,QAAAC,QAAA;IAAAH,OAAAE,aAElB1B,MAAMqB,KAAK;IAAA,OAAAK;GAAA;EAAA,CAAA,GAAA,IAAA;EAAAF,OAAAF,aAGftB,MAAMK,UAAQ,IAAA;EAAA,OAAAiB;CAAA,EAAA,CAAA;AAGrB;;;;;AAMA,IAAaM,oBAAoB;CAC/B;CACA;CACA;CACA;CAWA;CACA;AAAiC,CAClC,CAACC,KAAK,GAAG;AAUV,IAAaC,yBAAyB;CACpCC,QAAQ;CACRC,MAAM;AACR;AA2DA,SAAgBO,aAA6CxC,OAA6B;CACxF,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAA4B;EAC3D;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CAED,MAAM,CAACyC,KAAKC,UAAUtD,aAA0B;CAChD,MAAM,CAACwD,KAAKC,UAAUzD,aAAmE,IAAI;CAE7F,MAAMU,kBACJ2C,IAAI,CAAC,EAAEQ,QAAQ,kBAAkB,CAAC,EAAEC,aAAa,gBAAgB,MAAM;CAEzE,MAAMC,gBAAgB;EACpB,MAAMC,UAAUX,IAAI;EACpB,IAAI,CAACW,WAAW,CAACtD,UAAU,GAAG;EAC9B,MAAMuD,OAAOD,QAAQE,sBAAsB;EAC3CT,OAAO;GAAEC,KAAKO,KAAKP;GAAKC,MAAMM,KAAKE,QAAQ;GAAGP,QAAQK,KAAKL;EAAO,CAAC;CACrE;CAEA,MAAMQ,gBAAgBX,OAAO,IAAI;CAEjC,OAAA,CAAAzC,gBAEKvB,aAAW0B,WAAA;EAAA,IACVC,KAAE;GAAA,OAAEP,MAAMO,MAAM;EAAG;EAAAiD,KACdf;EAAM,KAAA,kBAAA;GAAA,OACGzC,MAAM+B,SAAS,SAAS2B,KAAAA;EAAS;EAAA,KAAA,uBAAA;GAAA,OAC5B1D,MAAMsC;EAAY;EAAA,KAAA,iBAAA;GAAA,OACxBtC,MAAM+B,SAAS,KAAK2B,KAAAA;EAAS;EAAA,KAAA,WAAA;GAAA,OACnCnE,GACLqC,mBACA,YACA5B,MAAM+B,SAASD,uBAAuBC,SAASD,uBAAuBE,MACtEhC,MAAMJ,KACR;EAAC;EACDiE,gBAAgBX;EAChBY,gBAAgBP;EAChBQ,SAASb;EACTc,QAAQT;CAAO,GACVtD,MAA+B,EAAA,IAAAI,WAAA;EAAA,OAAA;UAAA;IAAA,IAAA6D,QAAAC,QAAA;IAAA3C,OAAA0C,aAGjClE,MAAMK,QAAQ;IAAA,OAAA6D;GAAA,EAAA,CAAA;UAAA;IAAA,IAAAE,QAAAC,QAAA;IAAA7C,OAAA4C,aAIdpE,MAAMqB,KAAK;IAAA,OAAA+C;GAAA,EAAA,CAAA;GAAAjE,gBAablB,MAAI;IAAA,IAACwC,OAAI;KAAA,OAAEzB,MAAMkC;IAAK;IAAA,IAAA7B,WAAA;KAAA,IAAAiE,QAAAC,QAAA;KAAA/C,OAAA8C,aAKlBtE,MAAMkC,KAAK;KAAA,OAAAoC;IAAA;GAAA,CAAA;GAAAnE,gBAIflB,MAAI;IAAA,IAACwC,OAAI;KAAA,OAAE+C,WAAA,CAAA,CAAAxE,MAAMqC,QAAQ,CAAA,CAAA,KAAIrC,MAAMoC,aAAasB,KAAAA;IAAS;IAAA,IAAArD,WAAA;KAAA,IAAAoE,QAAAC,QAAA;KAAAlD,OAAAiD,aAKrDzE,MAAMqC,QAAQ;KAAA,OAAAoC;IAAA;GAAA,CAAA;GAAAtE,gBAIlBlB,MAAI;IAAA,IAACwC,OAAI;KAAA,OAAEzB,MAAMoC;IAAQ;IAAA,IAAA/B,WAAA;KAAA,IAAAsE,QAAAC,QAAA;KAAApD,OAAAmD,aACQ3E,MAAMoC,QAAQ;KAAA,OAAAuC;IAAA;GAAA,CAAA;EAAA;CAAA,EAAA,CAAA,CAAA,GAAAxE,gBAIjDlB,MAAI;EAAA,IAACwC,OAAI;GAAA,OAAEkB,IAAI;EAAC;EAAAtC,WACbwE,aAAQ1E,gBACPd,QAAM,EAAA,IAAAgB,WAAA;GAAA,IAAAyE,QAAAC,SAAA,GAAAC,SAAAF,MAAAG;GAAAzD,OAAAwD,cAmBAhF,MAAMK,QAAQ;GAAAmB,OAAAsD,aAEhB9E,MAAMqB,OAAK,IAAA;GAAAG,OAAAsD,OAAA3E,gBACXlB,MAAI;IAAA,IAACwC,OAAI;KAAA,OAAEzB,MAAMqC;IAAQ;IAAA,IAAAhC,WAAA;KAAA,IAAA6E,SAAAC,QAAA;KAAA3D,OAAA0D,cAErBlF,MAAMqC,QAAQ;KAAA,OAAA6C;IAAA;GAAA,CAAA,GAAA,IAAA;GAAAE,QAAAC,QAAA;IAAA,IAAAC,MApBZ/F,GACLD,YACA,iGACF,GAACiG,OAEM,GAAGV,SAAS,CAAC,CAAChC,IAAG,KAAI2C,OACpB,GAAGX,SAAS,CAAC,CAAC/B,KAAI,KAAI2C,OACpB,GAAGZ,SAAS,CAAC,CAAC9B,OAAM,KAAI2C,OAIzBnG,GAAG,mEAAmE,EAC3E,gBAAgBS,MAAM+B,OACxB,CAAC;IAACuD,QAAAD,IAAAM,KAAAC,UAAAd,OAAAO,IAAAM,IAAAL,GAAA;IAAAC,SAAAF,IAAAQ,KAAAC,iBAAAhB,OAAA,OAAAO,IAAAQ,IAAAN,IAAA;IAAAC,SAAAH,IAAAU,KAAAD,iBAAAhB,OAAA,QAAAO,IAAAU,IAAAP,IAAA;IAAAC,SAAAJ,IAAAW,KAAAF,iBAAAhB,OAAA,UAAAO,IAAAW,IAAAP,IAAA;IAAAC,SAAAL,IAAAY,KAAAL,UAAAZ,QAAAK,IAAAY,IAAAP,IAAA;IAAA,OAAAL;GAAA,GAAA;IAAAM,GAAAjC,KAAAA;IAAAmC,GAAAnC,KAAAA;IAAAqC,GAAArC,KAAAA;IAAAsC,GAAAtC,KAAAA;IAAAuC,GAAAvC,KAAAA;GAAA,CAAA;GAAA,OAAAoB;EAAA,EAAA,CAAA;CAYT,CAAA,CAAA;AAIT;;AAGA,SAAgBoB,eACdnG,OAKA;CACA,MAAM,CAACC,OAAOC,QAAQb,WAAWW,OAAO;EAAC;EAAS;EAAS;EAAY;EAAY;CAAQ,CAAC;CAC5F,MAAM,CAACyC,KAAKC,UAAUtD,aAA0B;CAChD,MAAM,CAACwD,KAAKC,UAAUzD,aAAmE,IAAI;CAE7F,MAAMU,kBACJ2C,IAAI,CAAC,EAAEQ,QAAQ,kBAAkB,CAAC,EAAEC,aAAa,gBAAgB,MAAM;CAEzE,MAAMC,gBAAgB;EACpB,MAAMC,UAAUX,IAAI;EACpB,IAAI,CAACW,WAAW,CAACtD,UAAU,GAAG;EAC9B,MAAMuD,OAAOD,QAAQE,sBAAsB;EAC3CT,OAAO;GAAEC,KAAKO,KAAKP;GAAKC,MAAMM,KAAKE,QAAQ;GAAGP,QAAQK,KAAKL;EAAO,CAAC;CACrE;CAEA,OAAA,QAAA;EAAA,IAAAqD,SAAAC,SAAA,GAAAC,SAAAF,OAAAnB,YAAAsB,SAAAD,OAAAE;EAAAJ,OAAAK,iBAAA,cAUoB7D,OAAO,IAAI,CAAC;EAAAwD,OAAAK,iBAAA,SADjBvD,OAAO;EAAAkD,OAAAK,iBAAA,sBADM7D,OAAO,IAAI,CAAC;EAAAwD,OAAAK,iBAAA,gBADlBvD,OAAO;EAAAwD,IAHlBjE,QAAM2D,MAAA;EAAAvF,OAAAuF,QAAA9F,WAAA;GAAA,KAAA,gBAAA;IAAA,OACCN,MAAMqB;GAAK;GAAA,KAAA,iBAAA;IAAA,OACVrB,MAAM+B,SAAS,SAAS2B,KAAAA;GAAS;GAAA,KAAA,WAAA;IAAA,OAKvCnE,GACLqC,mBACA5B,MAAM+B,SAASD,uBAAuBC,SAASD,uBAAuBE,MACtE,oDACAhC,MAAMJ,KACR;GAAC;EAAA,GACGK,IAAI,GAAA,OAAA,IAAA;EAAAuB,OAAA8E,cAGLtG,MAAMK,QAAQ;EAAAmB,OAAA+E,cAGdvG,MAAMqB,KAAK;EAAAG,OAAA4E,QAAAjG,gBAEblB,MAAI;GAAA,IAACwC,OAAI;IAAA,OAAEzB,MAAMqC;GAAQ;GAAA,IAAAhC,WAAA;IAAA,IAAAsG,SAAAjC,QAAA;IAAAlD,OAAAmF,cAKrB3G,MAAMqC,QAAQ;IAAA,OAAAsE;GAAA;EAAA,CAAA,GAAA,IAAA;EAAA,OAAAP;CAAA,EAAA,CAAA,GAAAjG,gBAKpBlB,MAAI;EAAA,IAACwC,OAAI;GAAA,OAAEkB,IAAI;EAAC;EAAAtC,WACbwE,aAAQ1E,gBACPd,QAAM,EAAA,IAAAgB,WAAA;GAAA,IAAAuG,SAAAC,SAAA,GAAAC,SAAAF,OAAA3B;GAAAzD,OAAAsF,cAeA9G,MAAMK,QAAQ;GAAAmB,OAAAoF,cAEhB5G,MAAMqB,OAAK,IAAA;GAAA+D,QAAAC,QAAA;IAAA,IAAA0B,OAbLxH,GACLD,YACA,iGACF,GAAC0H,OAEM,GAAGnC,SAAS,CAAC,CAAChC,IAAG,KAAIoE,OACpB,GAAGpC,SAAS,CAAC,CAAC/B,KAAI,KAAIoE,OACpB,GAAGrC,SAAS,CAAC,CAAC9B,OAAM;IAAIgE,SAAA1B,IAAAM,KAAAC,UAAAgB,QAAAvB,IAAAM,IAAAoB,IAAA;IAAAC,SAAA3B,IAAAQ,KAAAC,iBAAAc,QAAA,OAAAvB,IAAAQ,IAAAmB,IAAA;IAAAC,SAAA5B,IAAAU,KAAAD,iBAAAc,QAAA,QAAAvB,IAAAU,IAAAkB,IAAA;IAAAC,SAAA7B,IAAAW,KAAAF,iBAAAc,QAAA,UAAAvB,IAAAW,IAAAkB,IAAA;IAAA,OAAA7B;GAAA,GAAA;IAAAM,GAAAjC,KAAAA;IAAAmC,GAAAnC,KAAAA;IAAAqC,GAAArC,KAAAA;IAAAsC,GAAAtC,KAAAA;GAAA,CAAA;GAAA,OAAAkD;EAAA,EAAA,CAAA;CASvC,CAAA,CAAA;AAIT"}
|
|
1
|
+
{"version":3,"file":"side-rail.js","names":["Polymorphic","PolymorphicProps","ComponentProps","JSX","ValidComponent","Show","createMemo","createSignal","splitProps","Portal","tooltipTip","cn","SideRailContext","createSideRailValue","SideRailProps","T","class","collapsed","SideRail","props","local","rest","value","_$createComponent","Provider","children","_$mergeProps","as","aria-label","data-collapsed","SideRailHeader","_el$","_tmpl$","_$spread","SideRailContent","_el$2","_tmpl$2","SideRailFooter","_el$3","_tmpl$3","SideRailSection","label","_el$4","_tmpl$5","_$insert","when","_el$5","_tmpl$4","sideRailItemClass","join","sideRailItemStateClass","active","idle","SideRailItemProps","badge","Element","trailing","shortcut","keyshortcuts","SideRailItem","row","setRow","HTMLElement","tip","setTip","top","left","height","closest","getAttribute","showTip","element","rect","getBoundingClientRect","right","hideTip","ref","aria-current","undefined","aria-keyshortcuts","data-active","onPointerEnter","onPointerLeave","onFocus","onBlur","Record","_el$6","_tmpl$6","_el$7","_tmpl$7","_el$8","_tmpl$8","_$memo","_el$9","_tmpl$9","_el$0","_tmpl$0","keyed","position","_el$1","_tmpl$10","_el$10","firstChild","_el$11","_tmpl$1","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","e","_$className","t","_$setStyleProperty","a","o","i","SideRailButton","Omit","_el$12","_tmpl$11","_el$13","_el$14","nextSibling","addEventListener","_$use","_el$15","_el$16","_tmpl$12","_el$17","_v$6","_v$7","_v$8","_v$9","_$createComponent","_$mergeProps","_$memo","_$className","_$setStyleProperty"],"sources":["../../../../src/components/layout/side-rail/side-rail.tsx"],"sourcesContent":["import { Polymorphic, type PolymorphicProps } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, createMemo, createSignal, splitProps } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport { tooltipTip } from '#lib/overlay'\nimport { cn } from '#lib/utils'\nimport { SideRailContext, createSideRailValue } from './side-rail-context'\n\n/**\n * SideRail.\n *\n * The narrow, persistent column of top-level destinations at the window's leading\n * edge: the app mark, the primary sections, and a footer for account and settings.\n * It is the one piece of chrome that is always on screen, which is why it is a\n * component rather than something each view arranges.\n *\n * Two forms, one component. Collapsed it is an icon column; expanded it carries\n * labels. Both widths come from `--rail-width` (56px) and `--rail-width-expanded`\n * (236px), so an app cannot pick its own and end up a few pixels out of step with\n * the app beside it.\n *\n * The rail does not own its collapsed state; the app does. That state has to\n * survive a reload and usually lives with the rest of the window preferences, and\n * a rail that kept it privately could not be restored.\n */\nexport type SideRailProps<T extends ValidComponent = 'nav'> = PolymorphicProps<\n T,\n {\n class?: string\n collapsed?: boolean\n 'aria-label'?: string\n }\n>\n\nexport function SideRail<T extends ValidComponent = 'nav'>(props: SideRailProps<T>) {\n const [local, rest] = splitProps(props as SideRailProps, [\n 'class',\n 'collapsed',\n 'aria-label',\n 'children',\n ])\n\n const collapsed = () => local.collapsed ?? false\n const value = createSideRailValue(\n collapsed,\n createMemo(() => (collapsed() ? 'var(--rail-width)' : 'var(--rail-width-expanded)'))\n )\n\n return (\n <SideRailContext.Provider value={value}>\n <Polymorphic\n as=\"nav\"\n aria-label={local['aria-label'] ?? 'Primary'}\n /* Rendered in both states, with a real value, so the descendant selectors\n below can key on true *and* false — an absent attribute would leave the\n expanded form matching neither. */\n data-collapsed={collapsed() ? 'true' : 'false'}\n class={cn(\n 'group/rail bg-sidebar text-sidebar-foreground flex h-full shrink-0 flex-col border-e border-sidebar-border',\n 'transition-[width] duration-150 ease-out',\n { 'w-rail': collapsed(), 'w-rail-expanded': !collapsed() },\n local.class\n )}\n {...(rest as ComponentProps<'nav'>)}\n >\n {local.children}\n </Polymorphic>\n </SideRailContext.Provider>\n )\n}\n\n/** The header slot: the app mark, and the product name when there is room. */\nexport function SideRailHeader(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-header\"\n class={cn(\n 'h-topbar flex shrink-0 items-center gap-2.5 px-3 group-data-[collapsed=true]/rail:justify-center group-data-[collapsed=true]/rail:px-0',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** The scrolling middle. Keeps the header and the footer pinned. */\nexport function SideRailContent(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-content\"\n class={cn(\n 'flex min-h-0 flex-1 flex-col gap-0.5 overflow-x-hidden overflow-y-auto px-2 py-2',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** The pinned footer: account, settings, help. */\nexport function SideRailFooter(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"side-rail-footer\"\n class={cn(\n 'flex shrink-0 flex-col gap-0.5 border-t border-sidebar-border px-2 py-2',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A titled group of rail destinations. The title hides when collapsed. */\nexport function SideRailSection(props: ComponentProps<'div'> & { label?: string }) {\n const [local, rest] = splitProps(props, ['class', 'label', 'children'])\n\n return (\n <div data-slot=\"side-rail-section\" class={cn('flex flex-col gap-0.5', local.class)} {...rest}>\n <Show when={local.label}>\n <div class=\"text-sidebar-muted-foreground px-2 pt-2 pb-1 text-2xs font-medium tracking-wide uppercase group-data-[collapsed=true]/rail:hidden\">\n {local.label}\n </div>\n </Show>\n {local.children}\n </div>\n )\n}\n\n/**\n * The classes a rail row uses. Exported so a caller's own element — a router link,\n * a custom button — can match the rail exactly instead of approximating it.\n */\nexport const sideRailItemClass = [\n 'group/rail-item flex h-rail-item min-w-0 w-full items-center gap-2.5 rounded-md px-3 text-sm font-medium',\n 'group-data-[collapsed=true]/rail:justify-center group-data-[collapsed=true]/rail:px-0',\n 'transition-[color,background-color,transform] ease-out outline-none select-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n /*\n * The donor's row scales up slightly under the pointer and down under a press.\n * It is a CSS transform rather than a motion-library gesture because the two are\n * the same thing here and the transform costs nothing at runtime: no wrapper\n * element, no listener, and it works on whatever element a caller renders the row\n * as — an anchor, a button, a router's own link.\n *\n * The collapsed rail opts out: a 1.02 scale on a 56px column pushes the row past\n * the rail's own edge, which reads as a glitch rather than as feedback.\n */\n 'hover:scale-[1.02] active:scale-[0.97] group-data-[collapsed=true]/rail:hover:scale-100 group-data-[collapsed=true]/rail:active:scale-[0.98]',\n '[&_svg]:size-5 [&_svg]:shrink-0',\n].join(' ')\n\n/*\n * The rail's states are accent-driven: the icon carries `--primary` on hover and\n * on the active destination, and both states draw the accent's own tint rather\n * than a neutral fill, so the rail reads as the app's accent chroma instead of a\n * grey column. The active label stays on `sidebar-foreground` because the accent\n * presets guarantee their 3:1 interaction minimum against the surface, not the\n * 4.5:1 small text owes; the icon is a graphic and rides the accent.\n */\nexport const sideRailItemStateClass = {\n active: 'bg-primary-subtle text-sidebar-foreground [&_svg]:text-primary',\n idle: 'text-sidebar-muted-foreground hover:bg-primary-subtle/60 hover:text-primary',\n}\n\n/**\n * A rail destination.\n *\n * ## The tooltip is the rail's hover affordance, not a generic bubble\n *\n * Collapsed, the row has no text, so the label has to come from somewhere. This\n * ports the donor's treatment rather than using a standard tooltip, because the\n * details are what make it read as part of the rail:\n *\n * - It is **flush with the row**: positioned at the row's own top and given the\n * row's own height, so it continues the row outward instead of floating near\n * it. A centred bubble with an arrow reads as a separate object.\n * - It **repeats the icon**, which anchors it to the row it belongs to.\n * - It carries the **keyboard chord**, which is the one piece of information a\n * collapsed rail otherwise cannot show.\n * - It opens on **hover and on focus**, so a keyboard user gets the same label a\n * pointer user does.\n * - It is `pointer-events-none` and `aria-hidden`: the row already carries the\n * name (as a visually hidden span when collapsed), so this is decoration and\n * must never be the accessible name.\n *\n * ## The chord on the row\n *\n * Expanded, the row shows its chord on hover and on focus — and the chord is\n * declared once to assistive technology through `aria-keyshortcuts` rather than\n * being read out as glyphs. The visible badge is `aria-hidden` for that reason.\n */\nexport type SideRailItemProps<T extends ValidComponent = 'a'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the item as the current destination. */\n active?: boolean\n /**\n * The item's accessible name. Required, and always in the accessibility tree:\n * collapsed it moves into the tooltip and a visually hidden span rather than\n * being deleted.\n */\n label: string\n /**\n * A count or a dot. Expanded, it trails the label at the row's end; collapsed,\n * it moves onto the icon's corner, so the rail never loses it.\n */\n badge?: JSX.Element\n /** An indicator pinned to the trailing edge in the expanded form. */\n trailing?: JSX.Element\n /** The chord as it should be drawn, e.g. `⌘1`. Shown on hover and focus. */\n shortcut?: string\n /**\n * The same chord in the ARIA grammar, e.g. `Meta+1`. Declared to assistive\n * technology instead of the display glyphs, which are not a keyboard shortcut\n * a screen reader can parse. Supply it whenever `shortcut` is drawn.\n */\n keyshortcuts?: string\n }\n>\n\nexport function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItemProps<T>) {\n const [local, rest] = splitProps(props as SideRailItemProps, [\n 'as',\n 'class',\n 'active',\n 'label',\n 'badge',\n 'trailing',\n 'shortcut',\n 'keyshortcuts',\n 'children',\n ])\n\n const [row, setRow] = createSignal<HTMLElement>()\n const [tip, setTip] = createSignal<{ top: number; left: number; height: number } | null>(null)\n\n const collapsed = () =>\n row()?.closest('[data-collapsed]')?.getAttribute('data-collapsed') === 'true'\n\n const showTip = () => {\n const element = row()\n if (!element || !collapsed()) return\n const rect = element.getBoundingClientRect()\n setTip({ top: rect.top, left: rect.right + 8, height: rect.height })\n }\n\n const hideTip = () => setTip(null)\n\n return (\n <>\n <Polymorphic\n as={local.as ?? 'a'}\n ref={setRow}\n aria-current={local.active ? 'page' : undefined}\n aria-keyshortcuts={local.keyshortcuts}\n data-active={local.active ? '' : undefined}\n class={cn(\n sideRailItemClass,\n 'relative',\n local.active ? sideRailItemStateClass.active : sideRailItemStateClass.idle,\n local.class\n )}\n onPointerEnter={showTip}\n onPointerLeave={hideTip}\n onFocus={showTip}\n onBlur={hideTip}\n {...(rest as Record<string, unknown>)}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n\n <span class=\"min-w-0 flex-1 truncate text-start group-data-[collapsed=true]/rail:sr-only\">\n {local.label}\n </span>\n\n {/*\n * One element, two placements, because the badge is caller content and a DOM\n * node cannot be in two places. Expanded, it is a trailing count in the row's\n * flow, after the label — over the icon it would cover the glyph the row is\n * recognised by. Collapsed, there is no label to trail, so it leaves the flow\n * and pins to the icon's top-end corner: anchored to the row's centre (where\n * the centred icon sits) and pushed out by 14px, the icon's half-width plus\n * the 4px overhang, so a wider count grows back over the icon rather than past\n * the rail's edge.\n */}\n <Show when={local.badge}>\n <span\n data-slot=\"side-rail-badge\"\n class=\"flex shrink-0 items-center justify-center group-data-[collapsed=true]/rail:absolute group-data-[collapsed=true]/rail:end-1/2 group-data-[collapsed=true]/rail:top-1/2 group-data-[collapsed=true]/rail:-me-3.5 group-data-[collapsed=true]/rail:-mt-3.5\"\n >\n {local.badge}\n </span>\n </Show>\n\n <Show when={local.shortcut && local.trailing === undefined}>\n <span\n aria-hidden=\"true\"\n class=\"text-sidebar-muted-foreground shrink-0 font-code text-code leading-none opacity-0 transition-opacity group-hover/rail-item:opacity-100 group-focus-visible/rail-item:opacity-100 group-data-[collapsed=true]/rail:hidden\"\n >\n {local.shortcut}\n </span>\n </Show>\n\n <Show when={local.trailing}>\n <span class=\"ms-auto shrink-0\">{local.trailing}</span>\n </Show>\n </Polymorphic>\n\n {/* The portal can finish an effect after the tooltip closes; capture its position. */}\n <Show when={tip()} keyed>\n {(position) => (\n <Portal>\n <div\n aria-hidden=\"true\"\n data-slot=\"side-rail-tip\"\n class={cn(\n tooltipTip,\n 'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'\n )}\n style={{\n top: `${position.top}px`,\n left: `${position.left}px`,\n height: `${position.height}px`,\n }}\n >\n <span\n class={cn('flex size-5 shrink-0 items-center justify-center [&_svg]:size-5', {\n 'text-primary': local.active,\n })}\n >\n {local.children}\n </span>\n {local.label}\n <Show when={local.shortcut}>\n <span class=\"text-muted-foreground shrink-0 font-code text-code leading-none\">\n {local.shortcut}\n </span>\n </Show>\n </div>\n </Portal>\n )}\n </Show>\n </>\n )\n}\n\n/** A non-navigating rail control: a collapse toggle, a \"new\" action. */\nexport function SideRailButton(\n props: Omit<ComponentProps<'button'>, 'type'> & {\n label: string\n shortcut?: string\n active?: boolean\n }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'shortcut', 'children', 'active'])\n const [row, setRow] = createSignal<HTMLElement>()\n const [tip, setTip] = createSignal<{ top: number; left: number; height: number } | null>(null)\n\n const collapsed = () =>\n row()?.closest('[data-collapsed]')?.getAttribute('data-collapsed') === 'true'\n\n const showTip = () => {\n const element = row()\n if (!element || !collapsed()) return\n const rect = element.getBoundingClientRect()\n setTip({ top: rect.top, left: rect.right + 8, height: rect.height })\n }\n\n return (\n <>\n <button\n type=\"button\"\n ref={setRow}\n aria-label={local.label}\n data-active={local.active ? 'true' : undefined}\n onPointerEnter={showTip}\n onPointerLeave={() => setTip(null)}\n onFocus={showTip}\n onBlur={() => setTip(null)}\n class={cn(\n sideRailItemClass,\n local.active ? sideRailItemStateClass.active : sideRailItemStateClass.idle,\n 'disabled:pointer-events-none disabled:opacity-50',\n local.class\n )}\n {...rest}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n <span class=\"min-w-0 flex-1 truncate text-start group-data-[collapsed=true]/rail:sr-only\">\n {local.label}\n </span>\n <Show when={local.shortcut}>\n <span\n aria-hidden=\"true\"\n class=\"text-sidebar-muted-foreground shrink-0 font-code text-code leading-none opacity-0 transition-opacity group-hover/rail-item:opacity-100 group-focus-visible/rail-item:opacity-100 group-data-[collapsed=true]/rail:hidden\"\n >\n {local.shortcut}\n </span>\n </Show>\n </button>\n\n {/* The portal can finish an effect after the tooltip closes; capture its position. */}\n <Show when={tip()} keyed>\n {(position) => (\n <Portal>\n <div\n aria-hidden=\"true\"\n data-slot=\"side-rail-tip\"\n class={cn(\n tooltipTip,\n 'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'\n )}\n style={{\n top: `${position.top}px`,\n left: `${position.left}px`,\n height: `${position.height}px`,\n }}\n >\n <span class=\"flex size-5 shrink-0 items-center justify-center [&_svg]:size-5\">\n {local.children}\n </span>\n {local.label}\n </div>\n </Portal>\n )}\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -27,6 +27,8 @@ export type UpdateChannelControlProps = {
|
|
|
27
27
|
persist: (value: UpdateChannel) => Promise<UpdateChannel>
|
|
28
28
|
/** Disable beyond the dialog's own working state, e.g. a host save in flight. */
|
|
29
29
|
disabled?: Accessor<boolean>
|
|
30
|
+
/** Per-channel option labels, when the defaults don't fit the app. Values remain unchanged. */
|
|
31
|
+
labels?: Partial<Record<UpdateChannel, string>>
|
|
30
32
|
/** Per-channel row descriptions, when the defaults don't fit the app. */
|
|
31
33
|
descriptions?: Partial<Record<UpdateChannel, string>>
|
|
32
34
|
/**
|
|
@@ -40,8 +42,8 @@ export type UpdateChannelControlProps = {
|
|
|
40
42
|
/**
|
|
41
43
|
* The updater dialog's release-channel row: one setting, a select trailing.
|
|
42
44
|
* Every desktop application that ships channels presents the same three of
|
|
43
|
-
* them with
|
|
44
|
-
* redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
45
|
+
* them with consistent behavior, which is why the row lives here rather than
|
|
46
|
+
* being redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
45
47
|
* channel switch re-asks the feed and the offer never outlives its channel.
|
|
46
48
|
*/
|
|
47
49
|
export function UpdateChannelControl(props: UpdateChannelControlProps) {
|
|
@@ -118,7 +120,10 @@ export function UpdateChannelControl(props: UpdateChannelControlProps) {
|
|
|
118
120
|
!loaded() || saving() || props.controls.disabled() || (props.disabled?.() ?? false)
|
|
119
121
|
}
|
|
120
122
|
value={channel()}
|
|
121
|
-
options={CHANNEL_OPTIONS
|
|
123
|
+
options={CHANNEL_OPTIONS.map((option) => ({
|
|
124
|
+
...option,
|
|
125
|
+
label: props.labels?.[option.value] ?? option.label,
|
|
126
|
+
}))}
|
|
122
127
|
onChange={(event) => void save(event.currentTarget.value)}
|
|
123
128
|
/>
|
|
124
129
|
</SettingsRow>
|
|
@@ -312,7 +312,8 @@ export function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItem
|
|
|
312
312
|
</Show>
|
|
313
313
|
</Polymorphic>
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
{/* The portal can finish an effect after the tooltip closes; capture its position. */}
|
|
316
|
+
<Show when={tip()} keyed>
|
|
316
317
|
{(position) => (
|
|
317
318
|
<Portal>
|
|
318
319
|
<div
|
|
@@ -323,9 +324,9 @@ export function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItem
|
|
|
323
324
|
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
324
325
|
)}
|
|
325
326
|
style={{
|
|
326
|
-
top: `${position
|
|
327
|
-
left: `${position
|
|
328
|
-
height: `${position
|
|
327
|
+
top: `${position.top}px`,
|
|
328
|
+
left: `${position.left}px`,
|
|
329
|
+
height: `${position.height}px`,
|
|
329
330
|
}}
|
|
330
331
|
>
|
|
331
332
|
<span
|
|
@@ -406,7 +407,8 @@ export function SideRailButton(
|
|
|
406
407
|
</Show>
|
|
407
408
|
</button>
|
|
408
409
|
|
|
409
|
-
|
|
410
|
+
{/* The portal can finish an effect after the tooltip closes; capture its position. */}
|
|
411
|
+
<Show when={tip()} keyed>
|
|
410
412
|
{(position) => (
|
|
411
413
|
<Portal>
|
|
412
414
|
<div
|
|
@@ -417,9 +419,9 @@ export function SideRailButton(
|
|
|
417
419
|
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
418
420
|
)}
|
|
419
421
|
style={{
|
|
420
|
-
top: `${position
|
|
421
|
-
left: `${position
|
|
422
|
-
height: `${position
|
|
422
|
+
top: `${position.top}px`,
|
|
423
|
+
left: `${position.left}px`,
|
|
424
|
+
height: `${position.height}px`,
|
|
423
425
|
}}
|
|
424
426
|
>
|
|
425
427
|
<span class="flex size-5 shrink-0 items-center justify-center [&_svg]:size-5">
|
package/package.json
CHANGED
|
@@ -27,6 +27,8 @@ export type UpdateChannelControlProps = {
|
|
|
27
27
|
persist: (value: UpdateChannel) => Promise<UpdateChannel>
|
|
28
28
|
/** Disable beyond the dialog's own working state, e.g. a host save in flight. */
|
|
29
29
|
disabled?: Accessor<boolean>
|
|
30
|
+
/** Per-channel option labels, when the defaults don't fit the app. Values remain unchanged. */
|
|
31
|
+
labels?: Partial<Record<UpdateChannel, string>>
|
|
30
32
|
/** Per-channel row descriptions, when the defaults don't fit the app. */
|
|
31
33
|
descriptions?: Partial<Record<UpdateChannel, string>>
|
|
32
34
|
/**
|
|
@@ -40,8 +42,8 @@ export type UpdateChannelControlProps = {
|
|
|
40
42
|
/**
|
|
41
43
|
* The updater dialog's release-channel row: one setting, a select trailing.
|
|
42
44
|
* Every desktop application that ships channels presents the same three of
|
|
43
|
-
* them with
|
|
44
|
-
* redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
45
|
+
* them with consistent behavior, which is why the row lives here rather than
|
|
46
|
+
* being redrawn per app. A save always flows through the dialog's `recheck`, so a
|
|
45
47
|
* channel switch re-asks the feed and the offer never outlives its channel.
|
|
46
48
|
*/
|
|
47
49
|
export function UpdateChannelControl(props: UpdateChannelControlProps) {
|
|
@@ -118,7 +120,10 @@ export function UpdateChannelControl(props: UpdateChannelControlProps) {
|
|
|
118
120
|
!loaded() || saving() || props.controls.disabled() || (props.disabled?.() ?? false)
|
|
119
121
|
}
|
|
120
122
|
value={channel()}
|
|
121
|
-
options={CHANNEL_OPTIONS
|
|
123
|
+
options={CHANNEL_OPTIONS.map((option) => ({
|
|
124
|
+
...option,
|
|
125
|
+
label: props.labels?.[option.value] ?? option.label,
|
|
126
|
+
}))}
|
|
122
127
|
onChange={(event) => void save(event.currentTarget.value)}
|
|
123
128
|
/>
|
|
124
129
|
</SettingsRow>
|
|
@@ -312,7 +312,8 @@ export function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItem
|
|
|
312
312
|
</Show>
|
|
313
313
|
</Polymorphic>
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
{/* The portal can finish an effect after the tooltip closes; capture its position. */}
|
|
316
|
+
<Show when={tip()} keyed>
|
|
316
317
|
{(position) => (
|
|
317
318
|
<Portal>
|
|
318
319
|
<div
|
|
@@ -323,9 +324,9 @@ export function SideRailItem<T extends ValidComponent = 'a'>(props: SideRailItem
|
|
|
323
324
|
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
324
325
|
)}
|
|
325
326
|
style={{
|
|
326
|
-
top: `${position
|
|
327
|
-
left: `${position
|
|
328
|
-
height: `${position
|
|
327
|
+
top: `${position.top}px`,
|
|
328
|
+
left: `${position.left}px`,
|
|
329
|
+
height: `${position.height}px`,
|
|
329
330
|
}}
|
|
330
331
|
>
|
|
331
332
|
<span
|
|
@@ -406,7 +407,8 @@ export function SideRailButton(
|
|
|
406
407
|
</Show>
|
|
407
408
|
</button>
|
|
408
409
|
|
|
409
|
-
|
|
410
|
+
{/* The portal can finish an effect after the tooltip closes; capture its position. */}
|
|
411
|
+
<Show when={tip()} keyed>
|
|
410
412
|
{(position) => (
|
|
411
413
|
<Portal>
|
|
412
414
|
<div
|
|
@@ -417,9 +419,9 @@ export function SideRailButton(
|
|
|
417
419
|
'pointer-events-none fixed z-(--z-tooltip) flex items-center gap-2.5 ps-3 pe-3 whitespace-nowrap'
|
|
418
420
|
)}
|
|
419
421
|
style={{
|
|
420
|
-
top: `${position
|
|
421
|
-
left: `${position
|
|
422
|
-
height: `${position
|
|
422
|
+
top: `${position.top}px`,
|
|
423
|
+
left: `${position.left}px`,
|
|
424
|
+
height: `${position.height}px`,
|
|
423
425
|
}}
|
|
424
426
|
>
|
|
425
427
|
<span class="flex size-5 shrink-0 items-center justify-center [&_svg]:size-5">
|