@flanksource/clicky-ui 0.2.3 → 0.2.4

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.
@@ -5,6 +5,7 @@ const react = require("react");
5
5
  const utils = require("../lib/utils.cjs");
6
6
  const Icon = require("../data/Icon.cjs");
7
7
  const button = require("./button.cjs");
8
+ const UiChevronDown = require("../icons/components/UiChevronDown.cjs");
8
9
  const UiCheck = require("../icons/components/UiCheck.cjs");
9
10
  function IconMenuPickerInner({
10
11
  value,
@@ -111,7 +112,7 @@ function IconMenuPickerInner({
111
112
  throw new Error(`IconMenuPicker: value "${value}" not found in options for ${ariaLabel}`);
112
113
  }
113
114
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: utils.cn("relative inline-flex", showLabel && "w-full", className), children: [
114
- /* @__PURE__ */ jsxRuntime.jsx(
115
+ /* @__PURE__ */ jsxRuntime.jsxs(
115
116
  button.Button,
116
117
  {
117
118
  ref: triggerRef,
@@ -124,8 +125,18 @@ function IconMenuPickerInner({
124
125
  title: triggerTitle ?? `${ariaLabel}: ${selected.label}`,
125
126
  onClick: () => setOpen((current) => !current),
126
127
  onKeyDown: onTriggerKeyDown,
127
- className: utils.cn("text-muted-foreground hover:text-foreground", triggerClassName),
128
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: selected.icon })
128
+ className: utils.cn(
129
+ "text-muted-foreground hover:text-foreground",
130
+ showLabel && "w-full justify-start",
131
+ triggerClassName
132
+ ),
133
+ children: [
134
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: selected.icon, className: showLabel ? "shrink-0 text-foreground" : void 0 }),
135
+ showLabel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
136
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left capitalize", children: `${ariaLabel}: ${selected.label}` }),
137
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiChevronDown.UiChevronDown, className: "shrink-0 text-muted-foreground" })
138
+ ] })
139
+ ]
129
140
  }
130
141
  ),
131
142
  open && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1 +1 @@
1
- {"version":3,"file":"icon-menu-picker.cjs","sources":["../../src/components/icon-menu-picker.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiCheck } from \"../icons\";\nimport { Button } from \"./button\";\n\nexport type IconMenuOption<T extends string> = {\n value: T;\n icon: StaticIconComponent;\n label: string;\n description?: string;\n};\n\nexport type IconMenuPickerProps<T extends string> = {\n value: T;\n onChange: (next: T) => void;\n options: IconMenuOption<T>[];\n ariaLabel: string;\n triggerTitle?: string | undefined;\n footer?: ReactNode | undefined;\n showLabel?: boolean | undefined;\n className?: string | undefined;\n triggerClassName?: string | undefined;\n menuClassName?: string | undefined;\n};\n\nfunction IconMenuPickerInner<T extends string>(\n {\n value,\n onChange,\n options,\n ariaLabel,\n triggerTitle,\n footer,\n showLabel,\n className,\n triggerClassName,\n menuClassName,\n }: IconMenuPickerProps<T>,\n ref: React.Ref<HTMLDivElement>,\n) {\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const [open, setOpen] = useState(false);\n\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement);\n\n const activeIndex = useMemo(\n () =>\n Math.max(\n 0,\n options.findIndex((option) => option.value === value),\n ),\n [options, value],\n );\n\n const close = useCallback((returnFocus: boolean) => {\n setOpen(false);\n if (returnFocus) triggerRef.current?.focus();\n }, []);\n\n const select = useCallback(\n (next: T) => {\n onChange(next);\n close(true);\n },\n [close, onChange],\n );\n\n useEffect(() => {\n if (!open) return;\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.button !== 0) return;\n if (!rootRef.current?.contains(event.target as Node)) {\n close(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(true);\n }\n };\n\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [close, open]);\n\n useEffect(() => {\n if (!open) return;\n const node = itemRefs.current[activeIndex];\n node?.focus();\n }, [activeIndex, open]);\n\n const focusItem = (index: number) => {\n const wrapped = (index + options.length) % options.length;\n itemRefs.current[wrapped]?.focus();\n };\n\n const onMenuKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const focusedIndex = itemRefs.current.findIndex((node) => node === document.activeElement);\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) + 1);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) - 1);\n return;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n focusItem(0);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n focusItem(options.length - 1);\n return;\n }\n if (event.key === \"Tab\") {\n close(false);\n }\n };\n\n const onTriggerKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen(true);\n }\n };\n\n const selected = options[activeIndex];\n if (!selected) {\n throw new Error(`IconMenuPicker: value \"${value}\" not found in options for ${ariaLabel}`);\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", showLabel && \"w-full\", className)}>\n <Button\n ref={triggerRef}\n type=\"button\"\n variant=\"ghost\"\n size={showLabel ? \"default\" : \"icon\"}\n aria-label={ariaLabel}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n title={triggerTitle ?? `${ariaLabel}: ${selected.label}`}\n onClick={() => setOpen((current) => !current)}\n onKeyDown={onTriggerKeyDown}\n className={cn(\"text-muted-foreground hover:text-foreground\", triggerClassName)}\n >\n <Icon icon={selected.icon} />\n </Button>\n {open && (\n <div\n role=\"menu\"\n aria-label={ariaLabel}\n onKeyDown={onMenuKeyDown}\n className={cn(\n \"absolute left-0 top-[calc(100%+0.375rem)] z-50 min-w-[12rem] rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg shadow-black/5\",\n menuClassName,\n )}\n >\n {options.map((option, index) => {\n const active = option.value === value;\n return (\n <button\n key={option.value}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={active}\n tabIndex={active ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(option.value);\n }\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n active && \"text-foreground\",\n )}\n >\n <Icon icon={option.icon} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate capitalize\">{option.label}</span>\n {active ? (\n <Icon icon={UiCheck} className=\"shrink-0 text-foreground\" />\n ) : (\n <span className=\"inline-block size-4 shrink-0\" aria-hidden />\n )}\n </button>\n );\n })}\n {footer ? (\n <div className=\"mt-1 border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground\">\n {footer}\n </div>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nexport const IconMenuPicker = forwardRef(IconMenuPickerInner) as <T extends string>(\n props: IconMenuPickerProps<T> & { ref?: React.Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":["useRef","useState","useImperativeHandle","useMemo","useCallback","useEffect","jsxs","cn","jsx","Button","Icon","UiCheck","forwardRef"],"mappings":"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"}
1
+ {"version":3,"file":"icon-menu-picker.cjs","sources":["../../src/components/icon-menu-picker.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiCheck, UiChevronDown } from \"../icons\";\nimport { Button } from \"./button\";\n\nexport type IconMenuOption<T extends string> = {\n value: T;\n icon: StaticIconComponent;\n label: string;\n description?: string;\n};\n\nexport type IconMenuPickerProps<T extends string> = {\n value: T;\n onChange: (next: T) => void;\n options: IconMenuOption<T>[];\n ariaLabel: string;\n triggerTitle?: string | undefined;\n footer?: ReactNode | undefined;\n showLabel?: boolean | undefined;\n className?: string | undefined;\n triggerClassName?: string | undefined;\n menuClassName?: string | undefined;\n};\n\nfunction IconMenuPickerInner<T extends string>(\n {\n value,\n onChange,\n options,\n ariaLabel,\n triggerTitle,\n footer,\n showLabel,\n className,\n triggerClassName,\n menuClassName,\n }: IconMenuPickerProps<T>,\n ref: React.Ref<HTMLDivElement>,\n) {\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const [open, setOpen] = useState(false);\n\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement);\n\n const activeIndex = useMemo(\n () =>\n Math.max(\n 0,\n options.findIndex((option) => option.value === value),\n ),\n [options, value],\n );\n\n const close = useCallback((returnFocus: boolean) => {\n setOpen(false);\n if (returnFocus) triggerRef.current?.focus();\n }, []);\n\n const select = useCallback(\n (next: T) => {\n onChange(next);\n close(true);\n },\n [close, onChange],\n );\n\n useEffect(() => {\n if (!open) return;\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.button !== 0) return;\n if (!rootRef.current?.contains(event.target as Node)) {\n close(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(true);\n }\n };\n\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [close, open]);\n\n useEffect(() => {\n if (!open) return;\n const node = itemRefs.current[activeIndex];\n node?.focus();\n }, [activeIndex, open]);\n\n const focusItem = (index: number) => {\n const wrapped = (index + options.length) % options.length;\n itemRefs.current[wrapped]?.focus();\n };\n\n const onMenuKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const focusedIndex = itemRefs.current.findIndex((node) => node === document.activeElement);\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) + 1);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) - 1);\n return;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n focusItem(0);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n focusItem(options.length - 1);\n return;\n }\n if (event.key === \"Tab\") {\n close(false);\n }\n };\n\n const onTriggerKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen(true);\n }\n };\n\n const selected = options[activeIndex];\n if (!selected) {\n throw new Error(`IconMenuPicker: value \"${value}\" not found in options for ${ariaLabel}`);\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", showLabel && \"w-full\", className)}>\n <Button\n ref={triggerRef}\n type=\"button\"\n variant=\"ghost\"\n size={showLabel ? \"default\" : \"icon\"}\n aria-label={ariaLabel}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n title={triggerTitle ?? `${ariaLabel}: ${selected.label}`}\n onClick={() => setOpen((current) => !current)}\n onKeyDown={onTriggerKeyDown}\n className={cn(\n \"text-muted-foreground hover:text-foreground\",\n showLabel && \"w-full justify-start\",\n triggerClassName,\n )}\n >\n <Icon icon={selected.icon} className={showLabel ? \"shrink-0 text-foreground\" : undefined} />\n {showLabel && (\n <>\n <span className=\"min-w-0 flex-1 truncate text-left capitalize\">\n {`${ariaLabel}: ${selected.label}`}\n </span>\n <Icon icon={UiChevronDown} className=\"shrink-0 text-muted-foreground\" />\n </>\n )}\n </Button>\n {open && (\n <div\n role=\"menu\"\n aria-label={ariaLabel}\n onKeyDown={onMenuKeyDown}\n className={cn(\n \"absolute left-0 top-[calc(100%+0.375rem)] z-50 min-w-[12rem] rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg shadow-black/5\",\n menuClassName,\n )}\n >\n {options.map((option, index) => {\n const active = option.value === value;\n return (\n <button\n key={option.value}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={active}\n tabIndex={active ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(option.value);\n }\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n active && \"text-foreground\",\n )}\n >\n <Icon icon={option.icon} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate capitalize\">{option.label}</span>\n {active ? (\n <Icon icon={UiCheck} className=\"shrink-0 text-foreground\" />\n ) : (\n <span className=\"inline-block size-4 shrink-0\" aria-hidden />\n )}\n </button>\n );\n })}\n {footer ? (\n <div className=\"mt-1 border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground\">\n {footer}\n </div>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nexport const IconMenuPicker = forwardRef(IconMenuPickerInner) as <T extends string>(\n props: IconMenuPickerProps<T> & { ref?: React.Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":["useRef","useState","useImperativeHandle","useMemo","useCallback","useEffect","jsxs","cn","Button","jsx","Icon","Fragment","UiChevronDown","UiCheck","forwardRef"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"icon-menu-picker.d.ts","sourceRoot":"","sources":["../../src/components/icon-menu-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAI9D,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,IAAI;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,IAAI;IAClD,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAkMF,eAAO,MAAM,cAAc,EAAsC,CAAC,CAAC,SAAS,MAAM,EAChF,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;CAAE,KAChE,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"icon-menu-picker.d.ts","sourceRoot":"","sources":["../../src/components/icon-menu-picker.tsx"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAI9D,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,IAAI;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,IAAI;IAClD,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AA8MF,eAAO,MAAM,cAAc,EAAsC,CAAC,CAAC,SAAS,MAAM,EAChF,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;CAAE,KAChE,GAAG,CAAC,OAAO,CAAC"}
@@ -1,8 +1,9 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { forwardRef, useRef, useState, useImperativeHandle, useMemo, useCallback, useEffect } from "react";
3
3
  import { cn } from "../lib/utils.js";
4
4
  import { Icon } from "../data/Icon.js";
5
5
  import { Button } from "./button.js";
6
+ import { UiChevronDown } from "../icons/components/UiChevronDown.js";
6
7
  import { UiCheck } from "../icons/components/UiCheck.js";
7
8
  function IconMenuPickerInner({
8
9
  value,
@@ -109,7 +110,7 @@ function IconMenuPickerInner({
109
110
  throw new Error(`IconMenuPicker: value "${value}" not found in options for ${ariaLabel}`);
110
111
  }
111
112
  return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative inline-flex", showLabel && "w-full", className), children: [
112
- /* @__PURE__ */ jsx(
113
+ /* @__PURE__ */ jsxs(
113
114
  Button,
114
115
  {
115
116
  ref: triggerRef,
@@ -122,8 +123,18 @@ function IconMenuPickerInner({
122
123
  title: triggerTitle ?? `${ariaLabel}: ${selected.label}`,
123
124
  onClick: () => setOpen((current) => !current),
124
125
  onKeyDown: onTriggerKeyDown,
125
- className: cn("text-muted-foreground hover:text-foreground", triggerClassName),
126
- children: /* @__PURE__ */ jsx(Icon, { icon: selected.icon })
126
+ className: cn(
127
+ "text-muted-foreground hover:text-foreground",
128
+ showLabel && "w-full justify-start",
129
+ triggerClassName
130
+ ),
131
+ children: [
132
+ /* @__PURE__ */ jsx(Icon, { icon: selected.icon, className: showLabel ? "shrink-0 text-foreground" : void 0 }),
133
+ showLabel && /* @__PURE__ */ jsxs(Fragment, { children: [
134
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left capitalize", children: `${ariaLabel}: ${selected.label}` }),
135
+ /* @__PURE__ */ jsx(Icon, { icon: UiChevronDown, className: "shrink-0 text-muted-foreground" })
136
+ ] })
137
+ ]
127
138
  }
128
139
  ),
129
140
  open && /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"file":"icon-menu-picker.js","sources":["../../src/components/icon-menu-picker.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiCheck } from \"../icons\";\nimport { Button } from \"./button\";\n\nexport type IconMenuOption<T extends string> = {\n value: T;\n icon: StaticIconComponent;\n label: string;\n description?: string;\n};\n\nexport type IconMenuPickerProps<T extends string> = {\n value: T;\n onChange: (next: T) => void;\n options: IconMenuOption<T>[];\n ariaLabel: string;\n triggerTitle?: string | undefined;\n footer?: ReactNode | undefined;\n showLabel?: boolean | undefined;\n className?: string | undefined;\n triggerClassName?: string | undefined;\n menuClassName?: string | undefined;\n};\n\nfunction IconMenuPickerInner<T extends string>(\n {\n value,\n onChange,\n options,\n ariaLabel,\n triggerTitle,\n footer,\n showLabel,\n className,\n triggerClassName,\n menuClassName,\n }: IconMenuPickerProps<T>,\n ref: React.Ref<HTMLDivElement>,\n) {\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const [open, setOpen] = useState(false);\n\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement);\n\n const activeIndex = useMemo(\n () =>\n Math.max(\n 0,\n options.findIndex((option) => option.value === value),\n ),\n [options, value],\n );\n\n const close = useCallback((returnFocus: boolean) => {\n setOpen(false);\n if (returnFocus) triggerRef.current?.focus();\n }, []);\n\n const select = useCallback(\n (next: T) => {\n onChange(next);\n close(true);\n },\n [close, onChange],\n );\n\n useEffect(() => {\n if (!open) return;\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.button !== 0) return;\n if (!rootRef.current?.contains(event.target as Node)) {\n close(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(true);\n }\n };\n\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [close, open]);\n\n useEffect(() => {\n if (!open) return;\n const node = itemRefs.current[activeIndex];\n node?.focus();\n }, [activeIndex, open]);\n\n const focusItem = (index: number) => {\n const wrapped = (index + options.length) % options.length;\n itemRefs.current[wrapped]?.focus();\n };\n\n const onMenuKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const focusedIndex = itemRefs.current.findIndex((node) => node === document.activeElement);\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) + 1);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) - 1);\n return;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n focusItem(0);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n focusItem(options.length - 1);\n return;\n }\n if (event.key === \"Tab\") {\n close(false);\n }\n };\n\n const onTriggerKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen(true);\n }\n };\n\n const selected = options[activeIndex];\n if (!selected) {\n throw new Error(`IconMenuPicker: value \"${value}\" not found in options for ${ariaLabel}`);\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", showLabel && \"w-full\", className)}>\n <Button\n ref={triggerRef}\n type=\"button\"\n variant=\"ghost\"\n size={showLabel ? \"default\" : \"icon\"}\n aria-label={ariaLabel}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n title={triggerTitle ?? `${ariaLabel}: ${selected.label}`}\n onClick={() => setOpen((current) => !current)}\n onKeyDown={onTriggerKeyDown}\n className={cn(\"text-muted-foreground hover:text-foreground\", triggerClassName)}\n >\n <Icon icon={selected.icon} />\n </Button>\n {open && (\n <div\n role=\"menu\"\n aria-label={ariaLabel}\n onKeyDown={onMenuKeyDown}\n className={cn(\n \"absolute left-0 top-[calc(100%+0.375rem)] z-50 min-w-[12rem] rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg shadow-black/5\",\n menuClassName,\n )}\n >\n {options.map((option, index) => {\n const active = option.value === value;\n return (\n <button\n key={option.value}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={active}\n tabIndex={active ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(option.value);\n }\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n active && \"text-foreground\",\n )}\n >\n <Icon icon={option.icon} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate capitalize\">{option.label}</span>\n {active ? (\n <Icon icon={UiCheck} className=\"shrink-0 text-foreground\" />\n ) : (\n <span className=\"inline-block size-4 shrink-0\" aria-hidden />\n )}\n </button>\n );\n })}\n {footer ? (\n <div className=\"mt-1 border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground\">\n {footer}\n </div>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nexport const IconMenuPicker = forwardRef(IconMenuPickerInner) as <T extends string>(\n props: IconMenuPickerProps<T> & { ref?: React.Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"icon-menu-picker.js","sources":["../../src/components/icon-menu-picker.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiCheck, UiChevronDown } from \"../icons\";\nimport { Button } from \"./button\";\n\nexport type IconMenuOption<T extends string> = {\n value: T;\n icon: StaticIconComponent;\n label: string;\n description?: string;\n};\n\nexport type IconMenuPickerProps<T extends string> = {\n value: T;\n onChange: (next: T) => void;\n options: IconMenuOption<T>[];\n ariaLabel: string;\n triggerTitle?: string | undefined;\n footer?: ReactNode | undefined;\n showLabel?: boolean | undefined;\n className?: string | undefined;\n triggerClassName?: string | undefined;\n menuClassName?: string | undefined;\n};\n\nfunction IconMenuPickerInner<T extends string>(\n {\n value,\n onChange,\n options,\n ariaLabel,\n triggerTitle,\n footer,\n showLabel,\n className,\n triggerClassName,\n menuClassName,\n }: IconMenuPickerProps<T>,\n ref: React.Ref<HTMLDivElement>,\n) {\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const [open, setOpen] = useState(false);\n\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement);\n\n const activeIndex = useMemo(\n () =>\n Math.max(\n 0,\n options.findIndex((option) => option.value === value),\n ),\n [options, value],\n );\n\n const close = useCallback((returnFocus: boolean) => {\n setOpen(false);\n if (returnFocus) triggerRef.current?.focus();\n }, []);\n\n const select = useCallback(\n (next: T) => {\n onChange(next);\n close(true);\n },\n [close, onChange],\n );\n\n useEffect(() => {\n if (!open) return;\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.button !== 0) return;\n if (!rootRef.current?.contains(event.target as Node)) {\n close(false);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(true);\n }\n };\n\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [close, open]);\n\n useEffect(() => {\n if (!open) return;\n const node = itemRefs.current[activeIndex];\n node?.focus();\n }, [activeIndex, open]);\n\n const focusItem = (index: number) => {\n const wrapped = (index + options.length) % options.length;\n itemRefs.current[wrapped]?.focus();\n };\n\n const onMenuKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const focusedIndex = itemRefs.current.findIndex((node) => node === document.activeElement);\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) + 1);\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem((focusedIndex < 0 ? activeIndex : focusedIndex) - 1);\n return;\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n focusItem(0);\n return;\n }\n if (event.key === \"End\") {\n event.preventDefault();\n focusItem(options.length - 1);\n return;\n }\n if (event.key === \"Tab\") {\n close(false);\n }\n };\n\n const onTriggerKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (event.key === \"ArrowDown\" || event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen(true);\n }\n };\n\n const selected = options[activeIndex];\n if (!selected) {\n throw new Error(`IconMenuPicker: value \"${value}\" not found in options for ${ariaLabel}`);\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative inline-flex\", showLabel && \"w-full\", className)}>\n <Button\n ref={triggerRef}\n type=\"button\"\n variant=\"ghost\"\n size={showLabel ? \"default\" : \"icon\"}\n aria-label={ariaLabel}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n title={triggerTitle ?? `${ariaLabel}: ${selected.label}`}\n onClick={() => setOpen((current) => !current)}\n onKeyDown={onTriggerKeyDown}\n className={cn(\n \"text-muted-foreground hover:text-foreground\",\n showLabel && \"w-full justify-start\",\n triggerClassName,\n )}\n >\n <Icon icon={selected.icon} className={showLabel ? \"shrink-0 text-foreground\" : undefined} />\n {showLabel && (\n <>\n <span className=\"min-w-0 flex-1 truncate text-left capitalize\">\n {`${ariaLabel}: ${selected.label}`}\n </span>\n <Icon icon={UiChevronDown} className=\"shrink-0 text-muted-foreground\" />\n </>\n )}\n </Button>\n {open && (\n <div\n role=\"menu\"\n aria-label={ariaLabel}\n onKeyDown={onMenuKeyDown}\n className={cn(\n \"absolute left-0 top-[calc(100%+0.375rem)] z-50 min-w-[12rem] rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg shadow-black/5\",\n menuClassName,\n )}\n >\n {options.map((option, index) => {\n const active = option.value === value;\n return (\n <button\n key={option.value}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={active}\n tabIndex={active ? 0 : -1}\n onClick={() => select(option.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select(option.value);\n }\n }}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors\",\n \"hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n active && \"text-foreground\",\n )}\n >\n <Icon icon={option.icon} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate capitalize\">{option.label}</span>\n {active ? (\n <Icon icon={UiCheck} className=\"shrink-0 text-foreground\" />\n ) : (\n <span className=\"inline-block size-4 shrink-0\" aria-hidden />\n )}\n </button>\n );\n })}\n {footer ? (\n <div className=\"mt-1 border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground\">\n {footer}\n </div>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nexport const IconMenuPicker = forwardRef(IconMenuPickerInner) as <T extends string>(\n props: IconMenuPickerProps<T> & { ref?: React.Ref<HTMLDivElement> },\n) => JSX.Element;\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flanksource/clicky-ui",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.",
5
5
  "homepage": "https://github.com/flanksource/clicky-ui#readme",
6
6
  "bugs": "https://github.com/flanksource/clicky-ui/issues",