@kjun-ui/native 0.8.1 → 0.10.0

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.
Files changed (30) hide show
  1. package/dist/index.cjs +185 -64
  2. package/dist/index.js +185 -64
  3. package/dist/index.web.cjs +185 -64
  4. package/dist/index.web.js +185 -64
  5. package/dist/styles.css +30 -19
  6. package/dist/types/packages/native/src/button.d.cts +2 -0
  7. package/dist/types/packages/native/src/button.d.ts +2 -0
  8. package/dist/types/packages/native/src/display-primitives.d.cts +4 -1
  9. package/dist/types/packages/native/src/display-primitives.d.ts +4 -1
  10. package/dist/types/packages/native/src/floating-panel.d.cts +5 -1
  11. package/dist/types/packages/native/src/floating-panel.d.ts +5 -1
  12. package/dist/types/packages/native/src/input.d.cts +4 -1
  13. package/dist/types/packages/native/src/input.d.ts +4 -1
  14. package/dist/types/packages/native/src/popover.d.cts +9 -2
  15. package/dist/types/packages/native/src/popover.d.ts +9 -2
  16. package/dist/types/packages/native/src/select-control.d.cts +5 -1
  17. package/dist/types/packages/native/src/select-control.d.ts +5 -1
  18. package/dist/types/shared/package-runtime/alert-live.d.cts +3 -0
  19. package/dist/types/shared/package-runtime/alert-live.d.ts +3 -0
  20. package/dist/types/shared/package-runtime/aria-ids.d.cts +4 -0
  21. package/dist/types/shared/package-runtime/aria-ids.d.ts +4 -0
  22. package/dist/types/shared/package-runtime/layer-state.d.cts +3 -0
  23. package/dist/types/shared/package-runtime/layer-state.d.ts +3 -0
  24. package/dist/types/shared/package-runtime/options.d.cts +5 -1
  25. package/dist/types/shared/package-runtime/options.d.ts +5 -1
  26. package/dist/types/shared/package-runtime/table-presentation.d.cts +4 -0
  27. package/dist/types/shared/package-runtime/table-presentation.d.ts +4 -0
  28. package/dist/types/shared/package-runtime/use-layer.d.cts +3 -1
  29. package/dist/types/shared/package-runtime/use-layer.d.ts +3 -1
  30. package/package.json +3 -3
package/dist/styles.css CHANGED
@@ -250,6 +250,7 @@
250
250
  --_kjun-extension-popover-radius: 12px;
251
251
  --_kjun-extension-popover-padding: 16px;
252
252
  --_kjun-extension-popover-gap: 12px;
253
+ --_kjun-extension-popover-header-padding-bottom: 12px;
253
254
  --_kjun-extension-state-title-size: 1.25rem;
254
255
  --_kjun-extension-state-description-size: 0.75rem;
255
256
  --_kjun-extension-state-padding-sm: 24px;
@@ -946,28 +947,30 @@
946
947
  /* Baseline for kjun-owned markup only: an element with a class that starts with kjun- (kjun- is reserved;
947
948
  my-kjun-logo is app markup). Component roots carry a kjun- class (Vue adds kjun-root, the Vue layer host is kjun-layers);
948
949
  portal roots pair kjun-scope with a kjun- class. The bare Provider root (kjun-scope) is excluded, so app markup inside the Provider keeps its own styles.
949
- Slot content placed inside a kjun component follows this baseline; style it with classes. */
950
+ Slot content placed inside a kjun component follows this baseline; style it with classes.
951
+ App markup under [data-kjun-content] opts out of the descendant resets, while kjun elements inside it get them back;
952
+ both branches keep the same specificity as before (the exclusion sits in :where). */
950
953
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]),
951
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *,
954
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *:not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) *,
952
955
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"])::before,
953
956
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"])::after,
954
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *::before,
955
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *::after {
957
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *:not(:where([data-kjun-content] *))::before, .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) *::before,
958
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) *:not(:where([data-kjun-content] *))::after, .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) *::after {
956
959
  box-sizing: border-box;
957
960
  border-width: 0;
958
961
  border-style: solid;
959
962
  border-color: var(--_kjun-color-border);
960
963
  }
961
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(h1, h2, h3, h4, h5, h6, p, blockquote, dl, dd, figure, pre),
964
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(h1, h2, h3, h4, h5, h6, p, blockquote, dl, dd, figure, pre):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(h1, h2, h3, h4, h5, h6, p, blockquote, dl, dd, figure, pre),
962
965
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(h1, h2, h3, h4, h5, h6, p, blockquote, dl, dd, figure, pre) {
963
966
  margin: 0;
964
967
  }
965
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(h1, h2, h3, h4, h5, h6),
968
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(h1, h2, h3, h4, h5, h6):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(h1, h2, h3, h4, h5, h6),
966
969
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(h1, h2, h3, h4, h5, h6) {
967
970
  font-size: inherit;
968
971
  font-weight: inherit;
969
972
  }
970
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, input, optgroup, select, textarea),
973
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, input, optgroup, select, textarea):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(button, input, optgroup, select, textarea),
971
974
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(button, input, optgroup, select, textarea) {
972
975
  font: inherit;
973
976
  letter-spacing: inherit;
@@ -975,33 +978,33 @@
975
978
  margin: 0;
976
979
  padding: 0;
977
980
  }
978
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, select),
981
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, select):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(button, select),
979
982
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(button, select) { text-transform: none; }
980
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, [type="button"], [type="reset"], [type="submit"]),
983
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, [type="button"], [type="reset"], [type="submit"]):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(button, [type="button"], [type="reset"], [type="submit"]),
981
984
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(button, [type="button"], [type="reset"], [type="submit"]) {
982
985
  -webkit-appearance: button;
983
986
  background-color: transparent;
984
987
  background-image: none;
985
988
  }
986
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, [role="button"]),
989
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(button, [role="button"]):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(button, [role="button"]),
987
990
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(button, [role="button"]) { cursor: pointer; }
988
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(:disabled),
991
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(:disabled):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(:disabled),
989
992
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(:disabled) { cursor: default; }
990
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(a),
993
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(a):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(a),
991
994
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(a) { color: inherit; text-decoration: inherit; }
992
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(ol, ul, menu),
995
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(ol, ul, menu):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(ol, ul, menu),
993
996
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(ol, ul, menu) { list-style: none; margin: 0; padding: 0; }
994
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(table),
997
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(table):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(table),
995
998
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(table) { text-indent: 0; border-color: inherit; border-collapse: collapse; }
996
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(fieldset, legend),
999
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(fieldset, legend):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(fieldset, legend),
997
1000
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(fieldset, legend) { margin: 0; padding: 0; }
998
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(textarea),
1001
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(textarea):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(textarea),
999
1002
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(textarea) { resize: vertical; }
1000
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(input, textarea)::placeholder,
1003
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(input, textarea):not(:where([data-kjun-content] *))::placeholder, .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(input, textarea)::placeholder,
1001
1004
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(input, textarea)::placeholder { opacity: 1; }
1002
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(img, video),
1005
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where(img, video):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where(img, video),
1003
1006
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where(img, video) { max-width: 100%; height: auto; }
1004
- .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where([hidden]:not([hidden="until-found"])),
1007
+ .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]) :where([hidden]:not([hidden="until-found"])):not(:where([data-kjun-content] *)), .kjun-scope :where([data-kjun-content] :is([class^="kjun-"], [class*=" kjun-"])) :where([hidden]:not([hidden="until-found"])),
1005
1008
  .kjun-scope :where(:is([class^="kjun-"], [class*=" kjun-"]):not(.kjun-scope), .kjun-scope[class*=" kjun-"]):where([hidden]:not([hidden="until-found"])) { display: none; }
1006
1009
  /* Last so it wins over the element resets above (e.g. font: inherit on a root <button>).
1007
1010
  The outermost kjun element takes the scope's text style; nested kjun elements inherit it.
@@ -1770,6 +1773,9 @@
1770
1773
  justify-content: flex-end;
1771
1774
  gap: var(--_kjun-geometry-modal-actions-gap);
1772
1775
  }
1776
+ /* wrap: the inline height becomes a minimum (set by the component) and the label may break lines. */
1777
+ .kjun-button[data-wrap] { flex-shrink: 1; max-width: 100%; white-space: normal; overflow-wrap: anywhere; text-align: center; }
1778
+ .kjun-button[data-wrap] > .kjun-button-label { min-width: 0; }
1773
1779
  .kjun-form-actions > .kjun-button {
1774
1780
  --_kjun-action-height: var(--_kjun-geometry-button-heights-lg);
1775
1781
  height: auto !important;
@@ -2424,6 +2430,11 @@
2424
2430
  font-weight:var(--_kjun-type-body-weight); letter-spacing:var(--_kjun-type-body-tracking);
2425
2431
  }
2426
2432
  .kjun-popover-dialog { outline:none; }
2433
+ /* With a header only the body scrolls: the panel and dialog become clipping flex columns. */
2434
+ .kjun-popover-has-header { display:flex; flex-direction:column; overflow:hidden; }
2435
+ .kjun-popover-has-header .kjun-popover-dialog { display:flex; flex-direction:column; flex:1 1 auto; min-height:0; }
2436
+ .kjun-popover-header { flex:none; padding:var(--_kjun-extension-popover-padding) var(--_kjun-extension-popover-padding) var(--_kjun-extension-popover-header-padding-bottom); border-bottom:var(--_kjun-border-default-width) solid var(--_kjun-color-divider); font-size:var(--_kjun-type-card-title-size); line-height:var(--_kjun-type-card-title-line); font-weight:var(--_kjun-type-card-title-weight); letter-spacing:var(--_kjun-type-card-title-tracking); word-break:keep-all; overflow-wrap:anywhere; }
2437
+ .kjun-popover-body { flex:1 1 auto; min-height:0; overflow-y:auto; }
2427
2438
  .kjun-popover-content { display:flex; flex-direction:column; gap:var(--_kjun-extension-popover-gap); padding:var(--_kjun-extension-popover-padding); min-width:0; word-break:keep-all; overflow-wrap:anywhere; }
2428
2439
  .kjun-popover-content[data-no-padding="true"] { padding:0; gap:0; }
2429
2440
  .kjun-tooltip {
@@ -14,6 +14,8 @@ export interface KjunButtonProps extends Omit<PressableProps, "children" | "styl
14
14
  size?: ButtonSize;
15
15
  loading?: boolean;
16
16
  block?: boolean;
17
+ /** Long labels wrap: the size's height becomes a minimum and the button grows instead of overflowing. */
18
+ wrap?: boolean;
17
19
  prefixIcon?: string;
18
20
  suffixIcon?: string;
19
21
  prefixIconFilled?: boolean;
@@ -14,6 +14,8 @@ export interface KjunButtonProps extends Omit<PressableProps, "children" | "styl
14
14
  size?: ButtonSize;
15
15
  loading?: boolean;
16
16
  block?: boolean;
17
+ /** Long labels wrap: the size's height becomes a minimum and the button grows instead of overflowing. */
18
+ wrap?: boolean;
17
19
  prefixIcon?: string;
18
20
  suffixIcon?: string;
19
21
  prefixIconFilled?: boolean;
@@ -1,3 +1,4 @@
1
+ import { type AlertLive } from "../../../shared/package-runtime/alert-live.cjs";
1
2
  import { type ReactNode } from "react";
2
3
  import { type StyleProp, type ViewStyle } from "react-native";
3
4
  export type DisplaySize = "xs" | "sm" | "md" | "lg" | "xl";
@@ -32,12 +33,14 @@ export interface KjunAlertProps {
32
33
  size?: "sm" | "md" | "lg";
33
34
  title?: ReactNode;
34
35
  closable?: boolean;
36
+ /** How screen readers announce it: assertive (role alert), polite (status) or off; defaults to alert for danger, status otherwise. */
37
+ live?: AlertLive;
35
38
  children?: ReactNode;
36
39
  /** Buttons placed under the message; unsized KjunButtons follow the alert size. */
37
40
  actions?: ReactNode;
38
41
  onClose?: () => void;
39
42
  }
40
- export declare function KjunAlert({ type, variant, size, title, closable, children, actions, onClose, }: KjunAlertProps): import("react/jsx-runtime").JSX.Element | null;
43
+ export declare function KjunAlert({ type, variant, size, title, closable, live, children, actions, onClose, }: KjunAlertProps): import("react/jsx-runtime").JSX.Element | null;
41
44
  export interface KjunProgressProps {
42
45
  value?: number;
43
46
  max?: number;
@@ -1,3 +1,4 @@
1
+ import { type AlertLive } from "../../../shared/package-runtime/alert-live.js";
1
2
  import { type ReactNode } from "react";
2
3
  import { type StyleProp, type ViewStyle } from "react-native";
3
4
  export type DisplaySize = "xs" | "sm" | "md" | "lg" | "xl";
@@ -32,12 +33,14 @@ export interface KjunAlertProps {
32
33
  size?: "sm" | "md" | "lg";
33
34
  title?: ReactNode;
34
35
  closable?: boolean;
36
+ /** How screen readers announce it: assertive (role alert), polite (status) or off; defaults to alert for danger, status otherwise. */
37
+ live?: AlertLive;
35
38
  children?: ReactNode;
36
39
  /** Buttons placed under the message; unsized KjunButtons follow the alert size. */
37
40
  actions?: ReactNode;
38
41
  onClose?: () => void;
39
42
  }
40
- export declare function KjunAlert({ type, variant, size, title, closable, children, actions, onClose, }: KjunAlertProps): import("react/jsx-runtime").JSX.Element | null;
43
+ export declare function KjunAlert({ type, variant, size, title, closable, live, children, actions, onClose, }: KjunAlertProps): import("react/jsx-runtime").JSX.Element | null;
41
44
  export interface KjunProgressProps {
42
45
  value?: number;
43
46
  max?: number;
@@ -6,7 +6,7 @@ export declare function LayerTrigger({ trigger, onPress, disabled, }: {
6
6
  disabled?: boolean;
7
7
  }): import("react/jsx-runtime").JSX.Element;
8
8
  export type Placement = "top" | "bottom" | "left" | "right" | "bottom-start" | "bottom-end" | "top-start" | "top-end";
9
- export declare function FloatingPanel({ open, onOpenChange, triggerRef, children, placement, matchTriggerWidth, maxHeight, ariaLabel, menu, field, tooltip, popover, flip, minimumWidth, focusOnOpen, reveal, }: {
9
+ export declare function FloatingPanel({ open, onOpenChange, triggerRef, children, placement, matchTriggerWidth, maxHeight, ariaLabel, menu, field, tooltip, popover, flip, minimumWidth, focusOnOpen, reveal, header, nonModal, }: {
10
10
  open: boolean;
11
11
  onOpenChange: (v: boolean) => void;
12
12
  triggerRef: RefObject<View | null>;
@@ -28,4 +28,8 @@ export declare function FloatingPanel({ open, onOpenChange, triggerRef, children
28
28
  y: number;
29
29
  height: number;
30
30
  } | null>;
31
+ /** Popover header drawn above the scroll view, so only the body scrolls. */
32
+ header?: ReactNode;
33
+ /** Popover modal={false}: screen readers are not confined to the panel. */
34
+ nonModal?: boolean;
31
35
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -6,7 +6,7 @@ export declare function LayerTrigger({ trigger, onPress, disabled, }: {
6
6
  disabled?: boolean;
7
7
  }): import("react/jsx-runtime").JSX.Element;
8
8
  export type Placement = "top" | "bottom" | "left" | "right" | "bottom-start" | "bottom-end" | "top-start" | "top-end";
9
- export declare function FloatingPanel({ open, onOpenChange, triggerRef, children, placement, matchTriggerWidth, maxHeight, ariaLabel, menu, field, tooltip, popover, flip, minimumWidth, focusOnOpen, reveal, }: {
9
+ export declare function FloatingPanel({ open, onOpenChange, triggerRef, children, placement, matchTriggerWidth, maxHeight, ariaLabel, menu, field, tooltip, popover, flip, minimumWidth, focusOnOpen, reveal, header, nonModal, }: {
10
10
  open: boolean;
11
11
  onOpenChange: (v: boolean) => void;
12
12
  triggerRef: RefObject<View | null>;
@@ -28,4 +28,8 @@ export declare function FloatingPanel({ open, onOpenChange, triggerRef, children
28
28
  y: number;
29
29
  height: number;
30
30
  } | null>;
31
+ /** Popover header drawn above the scroll view, so only the body scrolls. */
32
+ header?: ReactNode;
33
+ /** Popover modal={false}: screen readers are not confined to the panel. */
34
+ nonModal?: boolean;
31
35
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -8,6 +8,7 @@ interface FieldValue {
8
8
  hint?: string;
9
9
  required?: boolean;
10
10
  describedBy?: string;
11
+ labelHidden?: boolean;
11
12
  }
12
13
  export declare const FieldContext: import("react").Context<FieldValue | null>;
13
14
  export declare const useKjunField: () => FieldValue | null;
@@ -17,10 +18,12 @@ export interface KjunFormGroupProps {
17
18
  required?: boolean;
18
19
  error?: string;
19
20
  hint?: string;
21
+ /** Hides the label visually while it still names the field. */
22
+ labelHidden?: boolean;
20
23
  children: ReactNode;
21
24
  style?: StyleProp<ViewStyle>;
22
25
  }
23
- export declare function KjunFormGroup({ label, id, required, error, hint, children, style, }: KjunFormGroupProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function KjunFormGroup({ label, id, required, error, hint, labelHidden, children, style, }: KjunFormGroupProps): import("react/jsx-runtime").JSX.Element;
24
27
  export interface KjunInputProps extends Omit<TextInputProps, "value" | "onChange"> {
25
28
  value: string | number;
26
29
  size?: InputSize;
@@ -8,6 +8,7 @@ interface FieldValue {
8
8
  hint?: string;
9
9
  required?: boolean;
10
10
  describedBy?: string;
11
+ labelHidden?: boolean;
11
12
  }
12
13
  export declare const FieldContext: import("react").Context<FieldValue | null>;
13
14
  export declare const useKjunField: () => FieldValue | null;
@@ -17,10 +18,12 @@ export interface KjunFormGroupProps {
17
18
  required?: boolean;
18
19
  error?: string;
19
20
  hint?: string;
21
+ /** Hides the label visually while it still names the field. */
22
+ labelHidden?: boolean;
20
23
  children: ReactNode;
21
24
  style?: StyleProp<ViewStyle>;
22
25
  }
23
- export declare function KjunFormGroup({ label, id, required, error, hint, children, style, }: KjunFormGroupProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function KjunFormGroup({ label, id, required, error, hint, labelHidden, children, style, }: KjunFormGroupProps): import("react/jsx-runtime").JSX.Element;
24
27
  export interface KjunInputProps extends Omit<TextInputProps, "value" | "onChange"> {
25
28
  value: string | number;
26
29
  size?: InputSize;
@@ -11,14 +11,21 @@ export interface KjunPopoverProps {
11
11
  focusOnOpen?: boolean;
12
12
  ariaLabel?: string;
13
13
  placement?: "top" | "bottom" | "left" | "right";
14
+ /** Fixed header above the body; only the body scrolls and maxHeight covers both. */
15
+ header?: ReactNode;
16
+ /** false stops confining screen readers to the panel; Native has no Tab order to release. */
17
+ modal?: boolean;
14
18
  trigger: ReactNode | ((open: boolean) => ReactNode);
15
19
  children: ReactNode | ((close: () => void) => ReactNode);
16
20
  }
17
- export declare function KjunPopover({ noPadding, open: controlled, onOpenChange, manualTrigger, matchTriggerWidth, maxHeight, flip, focusOnOpen, ariaLabel, placement, trigger, children, }: KjunPopoverProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function KjunPopover({ noPadding, open: controlled, onOpenChange, manualTrigger, matchTriggerWidth, maxHeight, flip, focusOnOpen, ariaLabel, placement, header, modal, trigger, children, }: KjunPopoverProps): import("react/jsx-runtime").JSX.Element;
18
22
  export interface KjunTooltipProps extends Pick<PressableProps, "onPress" | "disabled"> {
19
23
  content?: string;
20
24
  placement?: "top" | "bottom" | "left" | "right";
21
25
  delay?: number;
26
+ /** Controlled visibility; omit to let hover and focus drive it. */
27
+ open?: boolean;
28
+ onOpenChange?: (open: boolean) => void;
22
29
  children: ReactNode;
23
30
  }
24
- export declare function KjunTooltip({ content: message, placement, delay, children, onPress, disabled, }: KjunTooltipProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function KjunTooltip({ content: message, placement, delay, children, onPress, disabled, open: controlled, onOpenChange, }: KjunTooltipProps): import("react/jsx-runtime").JSX.Element;
@@ -11,14 +11,21 @@ export interface KjunPopoverProps {
11
11
  focusOnOpen?: boolean;
12
12
  ariaLabel?: string;
13
13
  placement?: "top" | "bottom" | "left" | "right";
14
+ /** Fixed header above the body; only the body scrolls and maxHeight covers both. */
15
+ header?: ReactNode;
16
+ /** false stops confining screen readers to the panel; Native has no Tab order to release. */
17
+ modal?: boolean;
14
18
  trigger: ReactNode | ((open: boolean) => ReactNode);
15
19
  children: ReactNode | ((close: () => void) => ReactNode);
16
20
  }
17
- export declare function KjunPopover({ noPadding, open: controlled, onOpenChange, manualTrigger, matchTriggerWidth, maxHeight, flip, focusOnOpen, ariaLabel, placement, trigger, children, }: KjunPopoverProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function KjunPopover({ noPadding, open: controlled, onOpenChange, manualTrigger, matchTriggerWidth, maxHeight, flip, focusOnOpen, ariaLabel, placement, header, modal, trigger, children, }: KjunPopoverProps): import("react/jsx-runtime").JSX.Element;
18
22
  export interface KjunTooltipProps extends Pick<PressableProps, "onPress" | "disabled"> {
19
23
  content?: string;
20
24
  placement?: "top" | "bottom" | "left" | "right";
21
25
  delay?: number;
26
+ /** Controlled visibility; omit to let hover and focus drive it. */
27
+ open?: boolean;
28
+ onOpenChange?: (open: boolean) => void;
22
29
  children: ReactNode;
23
30
  }
24
- export declare function KjunTooltip({ content: message, placement, delay, children, onPress, disabled, }: KjunTooltipProps): import("react/jsx-runtime").JSX.Element;
31
+ export declare function KjunTooltip({ content: message, placement, delay, children, onPress, disabled, open: controlled, onOpenChange, }: KjunTooltipProps): import("react/jsx-runtime").JSX.Element;
@@ -25,6 +25,10 @@ export interface KjunSelectProps<T extends SelectOption = SelectOption> {
25
25
  onChange?: (v: OptionValue | OptionValue[] | null) => void;
26
26
  onOpenChange?: (v: boolean) => void;
27
27
  onSearch?: (v: string) => void;
28
+ /** Replaces the default ranked label/searchKeys match; results keep the original order. */
29
+ filterFn?: (option: T, query: string) => boolean;
30
+ /** Extra option fields searched after the label. */
31
+ searchKeys?: string[];
28
32
  onClear?: () => void;
29
33
  }
30
- export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
34
+ export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, filterFn, searchKeys, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -25,6 +25,10 @@ export interface KjunSelectProps<T extends SelectOption = SelectOption> {
25
25
  onChange?: (v: OptionValue | OptionValue[] | null) => void;
26
26
  onOpenChange?: (v: boolean) => void;
27
27
  onSearch?: (v: string) => void;
28
+ /** Replaces the default ranked label/searchKeys match; results keep the original order. */
29
+ filterFn?: (option: T, query: string) => boolean;
30
+ /** Extra option fields searched after the label. */
31
+ searchKeys?: string[];
28
32
  onClear?: () => void;
29
33
  }
30
- export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
34
+ export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, filterFn, searchKeys, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ export type AlertLive = "assertive" | "polite" | "off";
2
+ /** Alert announcement role: `live` overrides the tone default (danger interrupts, others are polite); off announces nothing. */
3
+ export declare function alertRole(tone: string, live?: AlertLive): "alert" | "status" | undefined;
@@ -0,0 +1,3 @@
1
+ export type AlertLive = "assertive" | "polite" | "off";
2
+ /** Alert announcement role: `live` overrides the tone default (danger interrupts, others are polite); off announces nothing. */
3
+ export declare function alertRole(tone: string, live?: AlertLive): "alert" | "status" | undefined;
@@ -0,0 +1,4 @@
1
+ /** Joins space-separated id lists, keeping each id once; empty input gives undefined so the attribute is omitted. */
2
+ export declare function mergeIds(...lists: (string | null | undefined)[]): string | undefined;
3
+ /** Joins hint and error text for platforms that announce one accessibility hint string. */
4
+ export declare function joinHints(...parts: (string | null | undefined)[]): string | undefined;
@@ -0,0 +1,4 @@
1
+ /** Joins space-separated id lists, keeping each id once; empty input gives undefined so the attribute is omitted. */
2
+ export declare function mergeIds(...lists: (string | null | undefined)[]): string | undefined;
3
+ /** Joins hint and error text for platforms that announce one accessibility hint string. */
4
+ export declare function joinHints(...parts: (string | null | undefined)[]): string | undefined;
@@ -6,6 +6,8 @@ export interface FocusTarget {
6
6
  }) => void;
7
7
  isConnected?: boolean;
8
8
  }
9
+ /** A caller-chosen return target wins while it is still in the document; false means the caller moves focus itself. */
10
+ export declare function chooseReturnTarget(chosen: FocusTarget | null | false | undefined, fallback: FocusTarget | null | undefined): FocusTarget | null | undefined;
9
11
  export interface LayerEntry {
10
12
  id: string;
11
13
  kind: LayerKind;
@@ -24,6 +26,7 @@ export declare function createLayerState(): {
24
26
  entries: Map<string, LayerEntry>;
25
27
  topWindow: () => LayerEntry | undefined;
26
28
  top: () => LayerEntry | undefined;
29
+ topPopup: () => LayerEntry | undefined;
27
30
  windowOf: (id?: string) => string | undefined;
28
31
  isRestoredFocus(target?: FocusTarget | null): boolean;
29
32
  clearRestoredFocus(target?: FocusTarget | null): void;
@@ -6,6 +6,8 @@ export interface FocusTarget {
6
6
  }) => void;
7
7
  isConnected?: boolean;
8
8
  }
9
+ /** A caller-chosen return target wins while it is still in the document; false means the caller moves focus itself. */
10
+ export declare function chooseReturnTarget(chosen: FocusTarget | null | false | undefined, fallback: FocusTarget | null | undefined): FocusTarget | null | undefined;
9
11
  export interface LayerEntry {
10
12
  id: string;
11
13
  kind: LayerKind;
@@ -24,6 +26,7 @@ export declare function createLayerState(): {
24
26
  entries: Map<string, LayerEntry>;
25
27
  topWindow: () => LayerEntry | undefined;
26
28
  top: () => LayerEntry | undefined;
29
+ topPopup: () => LayerEntry | undefined;
27
30
  windowOf: (id?: string) => string | undefined;
28
31
  isRestoredFocus(target?: FocusTarget | null): boolean;
29
32
  clearRestoredFocus(target?: FocusTarget | null): void;
@@ -8,7 +8,9 @@ export declare const optionDisabled: (option: SelectOption) => boolean;
8
8
  export declare function optionKey(option: SelectOption, key: string, index: number): string;
9
9
  export declare function optionSelected(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string): boolean;
10
10
  export declare function nextOptionValue(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string, multiple: boolean): OptionValue | OptionValue[];
11
- export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, }: {
11
+ /** 0 label starts with the query, 1 label contains it, 2 a searchKeys field contains it, -1 no match; an empty query matches as 0. */
12
+ export declare function optionMatchRank(option: SelectOption, query: string, labelKey: string, searchKeys?: readonly string[]): 0 | 1 | -1 | 2;
13
+ export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, filterFn, searchKeys, }: {
12
14
  options: T[];
13
15
  value: OptionValue | OptionValue[] | null;
14
16
  labelKey: string;
@@ -18,6 +20,8 @@ export declare function selectOptions<T extends SelectOption>({ options, value,
18
20
  limit: number;
19
21
  loading: boolean;
20
22
  multiple: boolean;
23
+ filterFn?: (option: T, query: string) => boolean;
24
+ searchKeys?: readonly string[];
21
25
  }): {
22
26
  selected: (option: T) => boolean;
23
27
  matching: {
@@ -8,7 +8,9 @@ export declare const optionDisabled: (option: SelectOption) => boolean;
8
8
  export declare function optionKey(option: SelectOption, key: string, index: number): string;
9
9
  export declare function optionSelected(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string): boolean;
10
10
  export declare function nextOptionValue(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string, multiple: boolean): OptionValue | OptionValue[];
11
- export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, }: {
11
+ /** 0 label starts with the query, 1 label contains it, 2 a searchKeys field contains it, -1 no match; an empty query matches as 0. */
12
+ export declare function optionMatchRank(option: SelectOption, query: string, labelKey: string, searchKeys?: readonly string[]): 0 | 1 | -1 | 2;
13
+ export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, filterFn, searchKeys, }: {
12
14
  options: T[];
13
15
  value: OptionValue | OptionValue[] | null;
14
16
  labelKey: string;
@@ -18,6 +20,8 @@ export declare function selectOptions<T extends SelectOption>({ options, value,
18
20
  limit: number;
19
21
  loading: boolean;
20
22
  multiple: boolean;
23
+ filterFn?: (option: T, query: string) => boolean;
24
+ searchKeys?: readonly string[];
21
25
  }): {
22
26
  selected: (option: T) => boolean;
23
27
  matching: {
@@ -11,6 +11,10 @@ export declare function tablePresentation<Row extends object>(props: TableProps<
11
11
  sections: TableCardSection[];
12
12
  columnsForSection(row: Row, section: TableCardSection): TableColumn<Row>[];
13
13
  };
14
+ export declare function columnFormat<Format>(column: {
15
+ key: string;
16
+ format?: Format;
17
+ }): Format | undefined;
14
18
  export declare function tableCellValue<Row extends object>(props: TableProps<Row, unknown>, column: TableColumn<Row>, row: Row, index: number): {
15
19
  value: unknown;
16
20
  body: ReactNode;
@@ -11,6 +11,10 @@ export declare function tablePresentation<Row extends object>(props: TableProps<
11
11
  sections: TableCardSection[];
12
12
  columnsForSection(row: Row, section: TableCardSection): TableColumn<Row>[];
13
13
  };
14
+ export declare function columnFormat<Format>(column: {
15
+ key: string;
16
+ format?: Format;
17
+ }): Format | undefined;
14
18
  export declare function tableCellValue<Row extends object>(props: TableProps<Row, unknown>, column: TableColumn<Row>, row: Row, index: number): {
15
19
  value: unknown;
16
20
  body: ReactNode;
@@ -9,6 +9,7 @@ export declare function useLayerState(): {
9
9
  entries: Map<string, import("./layer-state.cjs").LayerEntry>;
10
10
  topWindow: () => import("./layer-state.cjs").LayerEntry | undefined;
11
11
  top: () => import("./layer-state.cjs").LayerEntry | undefined;
12
+ topPopup: () => import("./layer-state.cjs").LayerEntry | undefined;
12
13
  windowOf: (id?: string) => string | undefined;
13
14
  isRestoredFocus(target?: FocusTarget | null): boolean;
14
15
  clearRestoredFocus(target?: FocusTarget | null): void;
@@ -36,12 +37,13 @@ export declare function useActiveLayerScope(): boolean;
36
37
  export declare function focusTrigger(target: FocusTarget | null | undefined): FocusTarget | HTMLElement | null | undefined;
37
38
  export declare function useLayer(open: boolean, present: boolean, kind: LayerKind, close: () => void, trigger?: {
38
39
  current: FocusTarget | null;
39
- }): {
40
+ }, returnFocus?: () => FocusTarget | null | false | undefined): {
40
41
  id: string;
41
42
  state: {
42
43
  entries: Map<string, import("./layer-state.cjs").LayerEntry>;
43
44
  topWindow: () => import("./layer-state.cjs").LayerEntry | undefined;
44
45
  top: () => import("./layer-state.cjs").LayerEntry | undefined;
46
+ topPopup: () => import("./layer-state.cjs").LayerEntry | undefined;
45
47
  windowOf: (id?: string) => string | undefined;
46
48
  isRestoredFocus(target?: FocusTarget | null): boolean;
47
49
  clearRestoredFocus(target?: FocusTarget | null): void;
@@ -9,6 +9,7 @@ export declare function useLayerState(): {
9
9
  entries: Map<string, import("./layer-state.js").LayerEntry>;
10
10
  topWindow: () => import("./layer-state.js").LayerEntry | undefined;
11
11
  top: () => import("./layer-state.js").LayerEntry | undefined;
12
+ topPopup: () => import("./layer-state.js").LayerEntry | undefined;
12
13
  windowOf: (id?: string) => string | undefined;
13
14
  isRestoredFocus(target?: FocusTarget | null): boolean;
14
15
  clearRestoredFocus(target?: FocusTarget | null): void;
@@ -36,12 +37,13 @@ export declare function useActiveLayerScope(): boolean;
36
37
  export declare function focusTrigger(target: FocusTarget | null | undefined): FocusTarget | HTMLElement | null | undefined;
37
38
  export declare function useLayer(open: boolean, present: boolean, kind: LayerKind, close: () => void, trigger?: {
38
39
  current: FocusTarget | null;
39
- }): {
40
+ }, returnFocus?: () => FocusTarget | null | false | undefined): {
40
41
  id: string;
41
42
  state: {
42
43
  entries: Map<string, import("./layer-state.js").LayerEntry>;
43
44
  topWindow: () => import("./layer-state.js").LayerEntry | undefined;
44
45
  top: () => import("./layer-state.js").LayerEntry | undefined;
46
+ topPopup: () => import("./layer-state.js").LayerEntry | undefined;
45
47
  windowOf: (id?: string) => string | undefined;
46
48
  isRestoredFocus(target?: FocusTarget | null): boolean;
47
49
  clearRestoredFocus(target?: FocusTarget | null): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kjun-ui/native",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "license": "MIT",
5
5
  "homepage": "https://ui.kjun.dev",
6
6
  "repository": {
@@ -47,8 +47,8 @@
47
47
  "./package.json": "./package.json"
48
48
  },
49
49
  "dependencies": {
50
- "@kjun-ui/tokens": "0.8.1",
51
- "@kjun-ui/icons": "0.8.1"
50
+ "@kjun-ui/tokens": "0.10.0",
51
+ "@kjun-ui/icons": "0.10.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "react": "^19.2.3",