@northslopetech/altitude-ui 1.5.0 → 1.7.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.
package/README.md CHANGED
@@ -84,6 +84,27 @@ The Button component uses Altitude design tokens:
84
84
  - **Focus states**: `primary-500` ring color
85
85
  - **Hover states**: Consistent with design system color scales
86
86
 
87
+ ### Checkbox
88
+
89
+ The Checkbox component is built on Radix UI Checkbox with Altitude design tokens.
90
+
91
+ ```tsx
92
+ import { Checkbox } from "@nslp/altitude";
93
+
94
+ function Example() {
95
+ return (
96
+ <div className="flex items-center space-x-2">
97
+ <Checkbox id="terms" />
98
+ <label htmlFor="terms">Accept terms and conditions</label>
99
+ </div>
100
+ );
101
+ }
102
+ ```
103
+
104
+ #### Checkbox Props
105
+
106
+ All standard Radix UI Checkbox attributes are also supported.
107
+
87
108
  ### asChild Pattern
88
109
 
89
110
  Use the `asChild` prop for composition with other components (powered by Radix UI Slot):
package/dist/index.d.mts CHANGED
@@ -3,6 +3,7 @@ import * as React from 'react';
3
3
  import { JSX } from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
  import * as SelectPrimitive from '@radix-ui/react-select';
6
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
6
7
 
7
8
  declare enum ButtonSize {
8
9
  Small = "sm",
@@ -71,6 +72,12 @@ interface DatePickerProps {
71
72
  }
72
73
  declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLButtonElement>>;
73
74
 
75
+ declare const checkboxVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
76
+ interface CheckboxProps extends React.ComponentProps<typeof CheckboxPrimitive.Root> {
77
+ className?: string;
78
+ }
79
+ declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
80
+
74
81
  declare enum UploadState {
75
82
  Default = "default",
76
83
  DragOver = "dragOver",
@@ -124,4 +131,4 @@ interface InputComponent {
124
131
  }
125
132
  declare const TypedInput: InputComponent;
126
133
 
127
- export { Button, type ButtonProps, ButtonSize, DatePicker, type DatePickerProps, FormField, type FormFieldProps, TypedInput as Input, type InputFieldProps, type InputProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type TextareaFieldProps, Typography, type TypographyProps, Upload, type UploadProps, UploadState, buttonVariants, datePickerTriggerVariants, inputVariants, selectTriggerVariants, typographyVariants, uploadVariants };
134
+ export { Button, type ButtonProps, ButtonSize, Checkbox, type CheckboxProps, DatePicker, type DatePickerProps, FormField, type FormFieldProps, TypedInput as Input, type InputFieldProps, type InputProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type TextareaFieldProps, Typography, type TypographyProps, Upload, type UploadProps, UploadState, buttonVariants, checkboxVariants, datePickerTriggerVariants, inputVariants, selectTriggerVariants, typographyVariants, uploadVariants };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import * as React from 'react';
3
3
  import { JSX } from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
  import * as SelectPrimitive from '@radix-ui/react-select';
6
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
6
7
 
7
8
  declare enum ButtonSize {
8
9
  Small = "sm",
@@ -71,6 +72,12 @@ interface DatePickerProps {
71
72
  }
72
73
  declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLButtonElement>>;
73
74
 
75
+ declare const checkboxVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
76
+ interface CheckboxProps extends React.ComponentProps<typeof CheckboxPrimitive.Root> {
77
+ className?: string;
78
+ }
79
+ declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
80
+
74
81
  declare enum UploadState {
75
82
  Default = "default",
76
83
  DragOver = "dragOver",
@@ -124,4 +131,4 @@ interface InputComponent {
124
131
  }
125
132
  declare const TypedInput: InputComponent;
126
133
 
127
- export { Button, type ButtonProps, ButtonSize, DatePicker, type DatePickerProps, FormField, type FormFieldProps, TypedInput as Input, type InputFieldProps, type InputProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type TextareaFieldProps, Typography, type TypographyProps, Upload, type UploadProps, UploadState, buttonVariants, datePickerTriggerVariants, inputVariants, selectTriggerVariants, typographyVariants, uploadVariants };
134
+ export { Button, type ButtonProps, ButtonSize, Checkbox, type CheckboxProps, DatePicker, type DatePickerProps, FormField, type FormFieldProps, TypedInput as Input, type InputFieldProps, type InputProps, Select, SelectContent, type SelectContentProps, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, type TextareaFieldProps, Typography, type TypographyProps, Upload, type UploadProps, UploadState, buttonVariants, checkboxVariants, datePickerTriggerVariants, inputVariants, selectTriggerVariants, typographyVariants, uploadVariants };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Button: () => Button,
34
34
  ButtonSize: () => ButtonSize,
35
+ Checkbox: () => Checkbox,
35
36
  DatePicker: () => DatePicker,
36
37
  FormField: () => FormField,
37
38
  Input: () => TypedInput,
@@ -49,6 +50,7 @@ __export(index_exports, {
49
50
  Upload: () => Upload,
50
51
  UploadState: () => UploadState,
51
52
  buttonVariants: () => buttonVariants,
53
+ checkboxVariants: () => checkboxVariants,
52
54
  datePickerTriggerVariants: () => datePickerTriggerVariants,
53
55
  inputVariants: () => inputVariants,
54
56
  selectTriggerVariants: () => selectTriggerVariants,
@@ -682,10 +684,30 @@ var DatePicker = React5.forwardRef(
682
684
  );
683
685
  DatePicker.displayName = "DatePicker";
684
686
 
685
- // src/components/ui/upload.tsx
687
+ // src/components/ui/checkbox.tsx
686
688
  var React6 = __toESM(require("react"));
689
+ var CheckboxPrimitive = __toESM(require("@radix-ui/react-checkbox"));
690
+ var import_lucide_react3 = require("lucide-react");
687
691
  var import_class_variance_authority6 = require("class-variance-authority");
688
692
  var import_jsx_runtime6 = require("react/jsx-runtime");
693
+ var checkboxVariants = (0, import_class_variance_authority6.cva)(
694
+ "peer size-4 shrink-0 rounded-[4px] border border-edge-strong bg-canvas-light hover:bg-canvas-info transition-colors focus-visible:outline-none focus-visible:border-2 focus-visible:border-edge-interactive disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-canvas-primary data-[state=checked]:border-canvas-primary data-[state=checked]:text-light [&_svg]:pointer-events-none [&_svg]:size-3 [&_svg]:shrink-0"
695
+ );
696
+ var Checkbox = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
697
+ CheckboxPrimitive.Root,
698
+ {
699
+ ref,
700
+ className: cn(checkboxVariants(), className),
701
+ ...props,
702
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.CheckIcon, { className: "size-3" }) })
703
+ }
704
+ ));
705
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
706
+
707
+ // src/components/ui/upload.tsx
708
+ var React7 = __toESM(require("react"));
709
+ var import_class_variance_authority7 = require("class-variance-authority");
710
+ var import_jsx_runtime7 = require("react/jsx-runtime");
689
711
  var UploadState = /* @__PURE__ */ ((UploadState2) => {
690
712
  UploadState2["Default"] = "default";
691
713
  UploadState2["DragOver"] = "dragOver";
@@ -695,7 +717,7 @@ var UploadState = /* @__PURE__ */ ((UploadState2) => {
695
717
  return UploadState2;
696
718
  })(UploadState || {});
697
719
  var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
698
- var uploadVariants = (0, import_class_variance_authority6.cva)(
720
+ var uploadVariants = (0, import_class_variance_authority7.cva)(
699
721
  "relative flex flex-col items-center justify-center rounded-lg transition-all duration-200 ease-in-out overflow-hidden",
700
722
  {
701
723
  variants: {
@@ -717,7 +739,7 @@ var uploadVariants = (0, import_class_variance_authority6.cva)(
717
739
  }
718
740
  }
719
741
  );
720
- var Upload = React6.forwardRef(
742
+ var Upload = React7.forwardRef(
721
743
  ({
722
744
  className,
723
745
  endpoint,
@@ -735,23 +757,23 @@ var Upload = React6.forwardRef(
735
757
  loading = false,
736
758
  ...props
737
759
  }, ref) => {
738
- const [currentState, setCurrentState] = React6.useState(state);
739
- const [currentProgress, setCurrentProgress] = React6.useState(progress);
740
- const fileInputRef = React6.useRef(null);
741
- const [selectedFiles, setSelectedFiles] = React6.useState([]);
742
- React6.useEffect(() => {
760
+ const [currentState, setCurrentState] = React7.useState(state);
761
+ const [currentProgress, setCurrentProgress] = React7.useState(progress);
762
+ const fileInputRef = React7.useRef(null);
763
+ const [selectedFiles, setSelectedFiles] = React7.useState([]);
764
+ React7.useEffect(() => {
743
765
  if (loading) {
744
766
  setCurrentState("uploading" /* Uploading */);
745
767
  } else {
746
768
  setCurrentState(state);
747
769
  }
748
770
  }, [state, loading]);
749
- React6.useEffect(() => {
771
+ React7.useEffect(() => {
750
772
  if (loading || progress !== void 0) {
751
773
  setCurrentProgress(progress);
752
774
  }
753
775
  }, [progress, loading]);
754
- const uploadFile = React6.useCallback(
776
+ const uploadFile = React7.useCallback(
755
777
  (file) => {
756
778
  if (!endpoint) {
757
779
  console.warn("Upload endpoint not provided");
@@ -894,17 +916,17 @@ var Upload = React6.forwardRef(
894
916
  const renderContent = () => {
895
917
  switch (currentState) {
896
918
  case "error" /* Error */:
897
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
919
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
898
920
  "div",
899
921
  {
900
922
  className: "flex flex-col items-center text-center max-w-[289px]",
901
923
  style: { gap: "32px" },
902
924
  children: [
903
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-4", children: [
904
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "heading-sm", children: "Upload fail" }),
905
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "body-md", className: "text-error", children: errorMessage })
925
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-4", children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "heading-sm", children: "Upload fail" }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "body-md", className: "text-error", children: errorMessage })
906
928
  ] }),
907
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
929
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
908
930
  Button,
909
931
  {
910
932
  variant: "destructive",
@@ -918,22 +940,22 @@ var Upload = React6.forwardRef(
918
940
  }
919
941
  );
920
942
  case "uploading" /* Uploading */:
921
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
943
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
922
944
  "div",
923
945
  {
924
946
  className: "flex flex-col items-center text-center max-w-[289px]",
925
947
  style: { gap: "32px" },
926
948
  children: [
927
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "heading-sm", className: "text-dark", children: "Uploading files" }),
928
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w-full max-w-[720px] space-y-2", children: [
929
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w-full bg-canvas-gray rounded-full h-2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
949
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "heading-sm", className: "text-dark", children: "Uploading files" }),
950
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "w-full max-w-[720px] space-y-2", children: [
951
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "w-full bg-canvas-gray rounded-full h-2", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
930
952
  "div",
931
953
  {
932
954
  className: "bg-canvas-primary h-2 rounded-full transition-all duration-300 ease-in-out",
933
955
  style: { width: `${currentProgress}%` }
934
956
  }
935
957
  ) }),
936
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
958
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
937
959
  Typography,
938
960
  {
939
961
  variant: "body-sm",
@@ -949,29 +971,29 @@ var Upload = React6.forwardRef(
949
971
  }
950
972
  );
951
973
  case "success" /* Success */:
952
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
974
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
953
975
  "div",
954
976
  {
955
977
  className: "flex flex-col items-center text-center max-w-[289px]",
956
978
  style: { gap: "32px" },
957
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-4", children: [
958
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "heading-sm", className: "text-success", children: "Upload successful!" }),
959
- selectedFiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-center", children: selectedFiles.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "body-sm", children: file.name }, index)) })
979
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-4", children: [
980
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "heading-sm", className: "text-success", children: "Upload successful!" }),
981
+ selectedFiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-center", children: selectedFiles.map((file, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "body-sm", children: file.name }, index)) })
960
982
  ] })
961
983
  }
962
984
  );
963
985
  default:
964
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
986
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
965
987
  "div",
966
988
  {
967
989
  className: "flex flex-col items-center text-center max-w-[289px]",
968
990
  style: { gap: "32px" },
969
991
  children: [
970
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-4", children: [
971
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "heading-sm", className: "text-dark", children: "Drag & drop files here" }),
972
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { variant: "body-md", className: "text-secondary", children: "or click to browse from your computer" })
992
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-4", children: [
993
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "heading-sm", className: "text-dark", children: "Drag & drop files here" }),
994
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Typography, { variant: "body-md", className: "text-secondary", children: "or click to browse from your computer" })
973
995
  ] }),
974
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
996
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
975
997
  Button,
976
998
  {
977
999
  variant: "default",
@@ -985,10 +1007,10 @@ var Upload = React6.forwardRef(
985
1007
  children: "Choose files"
986
1008
  }
987
1009
  ),
988
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Typography, { variant: "body-sm", className: "text-secondary", children: [
1010
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Typography, { variant: "body-sm", className: "text-secondary", children: [
989
1011
  "Supported file: ",
990
1012
  getFileTypeDisplay(),
991
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("br", {}),
1013
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("br", {}),
992
1014
  "Max: ",
993
1015
  Math.round(maxFileSize / 1024 / 1024),
994
1016
  " MB each"
@@ -998,7 +1020,7 @@ var Upload = React6.forwardRef(
998
1020
  );
999
1021
  }
1000
1022
  };
1001
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1023
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1002
1024
  "div",
1003
1025
  {
1004
1026
  ref,
@@ -1022,7 +1044,7 @@ var Upload = React6.forwardRef(
1022
1044
  "aria-disabled": disabled,
1023
1045
  ...props,
1024
1046
  children: [
1025
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1047
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1026
1048
  "input",
1027
1049
  {
1028
1050
  ref: fileInputRef,
@@ -1042,11 +1064,11 @@ var Upload = React6.forwardRef(
1042
1064
  Upload.displayName = "Upload";
1043
1065
 
1044
1066
  // src/components/ui/input.tsx
1045
- var React7 = __toESM(require("react"));
1046
- var import_class_variance_authority7 = require("class-variance-authority");
1047
- var import_lucide_react3 = require("lucide-react");
1048
- var import_jsx_runtime7 = require("react/jsx-runtime");
1049
- var inputVariants = (0, import_class_variance_authority7.cva)(
1067
+ var React8 = __toESM(require("react"));
1068
+ var import_class_variance_authority8 = require("class-variance-authority");
1069
+ var import_lucide_react4 = require("lucide-react");
1070
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1071
+ var inputVariants = (0, import_class_variance_authority8.cva)(
1050
1072
  "flex w-full border bg-canvas-light text-dark focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:border-edge-default transition-colors rounded-md px-4 py-2 min-w-80 border-edge-default focus-visible:border-2 focus-visible:border-edge-strong placeholder:text-secondary read-only:bg-canvas-gray read-only:cursor-default read-only:border-transparent read-only:text-secondary read-only:focus-visible:border-transparent",
1051
1073
  {
1052
1074
  variants: {
@@ -1060,7 +1082,7 @@ var inputVariants = (0, import_class_variance_authority7.cva)(
1060
1082
  }
1061
1083
  }
1062
1084
  );
1063
- var Input = React7.forwardRef(
1085
+ var Input = React8.forwardRef(
1064
1086
  ({
1065
1087
  className,
1066
1088
  variant = "input",
@@ -1071,7 +1093,7 @@ var Input = React7.forwardRef(
1071
1093
  readOnly,
1072
1094
  ...props
1073
1095
  }, ref) => {
1074
- const [internalValue, setInternalValue] = React7.useState(value || "");
1096
+ const [internalValue, setInternalValue] = React8.useState(value || "");
1075
1097
  const isControlled = value !== void 0;
1076
1098
  const currentValue = isControlled ? value : internalValue;
1077
1099
  const showClear = currentValue && currentValue.toString().length > 0 && !readOnly;
@@ -1120,8 +1142,8 @@ var Input = React7.forwardRef(
1120
1142
  onClear?.();
1121
1143
  };
1122
1144
  if (variant === "textarea") {
1123
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative", children: [
1124
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1145
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative", children: [
1146
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1125
1147
  "textarea",
1126
1148
  {
1127
1149
  className: cn(
@@ -1137,20 +1159,20 @@ var Input = React7.forwardRef(
1137
1159
  ...props
1138
1160
  }
1139
1161
  ),
1140
- showClear && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1162
+ showClear && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1141
1163
  "button",
1142
1164
  {
1143
1165
  type: "button",
1144
1166
  onClick: handleClear,
1145
1167
  className: "absolute right-3 top-3 h-4 w-4 text-secondary hover:text-dark transition-colors",
1146
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.X, { className: "h-4 w-4" })
1168
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
1147
1169
  }
1148
1170
  ),
1149
- showLock && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Lock, { className: "absolute right-3 top-3 h-4 w-4 text-secondary" })
1171
+ showLock && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.Lock, { className: "absolute right-3 top-3 h-4 w-4 text-secondary" })
1150
1172
  ] });
1151
1173
  }
1152
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative", children: [
1153
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1174
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative", children: [
1175
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1154
1176
  "input",
1155
1177
  {
1156
1178
  className: cn(
@@ -1166,16 +1188,16 @@ var Input = React7.forwardRef(
1166
1188
  ...props
1167
1189
  }
1168
1190
  ),
1169
- showClear && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1191
+ showClear && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1170
1192
  "button",
1171
1193
  {
1172
1194
  type: "button",
1173
1195
  onClick: handleClear,
1174
1196
  className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary hover:text-dark transition-colors",
1175
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.X, { className: "h-4 w-4" })
1197
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
1176
1198
  }
1177
1199
  ),
1178
- showLock && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.Lock, { className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary" })
1200
+ showLock && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.Lock, { className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary" })
1179
1201
  ] });
1180
1202
  }
1181
1203
  );
@@ -1185,6 +1207,7 @@ var TypedInput = Input;
1185
1207
  0 && (module.exports = {
1186
1208
  Button,
1187
1209
  ButtonSize,
1210
+ Checkbox,
1188
1211
  DatePicker,
1189
1212
  FormField,
1190
1213
  Input,
@@ -1202,6 +1225,7 @@ var TypedInput = Input;
1202
1225
  Upload,
1203
1226
  UploadState,
1204
1227
  buttonVariants,
1228
+ checkboxVariants,
1205
1229
  datePickerTriggerVariants,
1206
1230
  inputVariants,
1207
1231
  selectTriggerVariants,
package/dist/index.mjs CHANGED
@@ -623,10 +623,30 @@ var DatePicker = React5.forwardRef(
623
623
  );
624
624
  DatePicker.displayName = "DatePicker";
625
625
 
626
- // src/components/ui/upload.tsx
626
+ // src/components/ui/checkbox.tsx
627
627
  import * as React6 from "react";
628
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
629
+ import { CheckIcon } from "lucide-react";
628
630
  import { cva as cva6 } from "class-variance-authority";
629
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
631
+ import { jsx as jsx6 } from "react/jsx-runtime";
632
+ var checkboxVariants = cva6(
633
+ "peer size-4 shrink-0 rounded-[4px] border border-edge-strong bg-canvas-light hover:bg-canvas-info transition-colors focus-visible:outline-none focus-visible:border-2 focus-visible:border-edge-interactive disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-canvas-primary data-[state=checked]:border-canvas-primary data-[state=checked]:text-light [&_svg]:pointer-events-none [&_svg]:size-3 [&_svg]:shrink-0"
634
+ );
635
+ var Checkbox = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
636
+ CheckboxPrimitive.Root,
637
+ {
638
+ ref,
639
+ className: cn(checkboxVariants(), className),
640
+ ...props,
641
+ children: /* @__PURE__ */ jsx6(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: /* @__PURE__ */ jsx6(CheckIcon, { className: "size-3" }) })
642
+ }
643
+ ));
644
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
645
+
646
+ // src/components/ui/upload.tsx
647
+ import * as React7 from "react";
648
+ import { cva as cva7 } from "class-variance-authority";
649
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
630
650
  var UploadState = /* @__PURE__ */ ((UploadState2) => {
631
651
  UploadState2["Default"] = "default";
632
652
  UploadState2["DragOver"] = "dragOver";
@@ -636,7 +656,7 @@ var UploadState = /* @__PURE__ */ ((UploadState2) => {
636
656
  return UploadState2;
637
657
  })(UploadState || {});
638
658
  var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
639
- var uploadVariants = cva6(
659
+ var uploadVariants = cva7(
640
660
  "relative flex flex-col items-center justify-center rounded-lg transition-all duration-200 ease-in-out overflow-hidden",
641
661
  {
642
662
  variants: {
@@ -658,7 +678,7 @@ var uploadVariants = cva6(
658
678
  }
659
679
  }
660
680
  );
661
- var Upload = React6.forwardRef(
681
+ var Upload = React7.forwardRef(
662
682
  ({
663
683
  className,
664
684
  endpoint,
@@ -676,23 +696,23 @@ var Upload = React6.forwardRef(
676
696
  loading = false,
677
697
  ...props
678
698
  }, ref) => {
679
- const [currentState, setCurrentState] = React6.useState(state);
680
- const [currentProgress, setCurrentProgress] = React6.useState(progress);
681
- const fileInputRef = React6.useRef(null);
682
- const [selectedFiles, setSelectedFiles] = React6.useState([]);
683
- React6.useEffect(() => {
699
+ const [currentState, setCurrentState] = React7.useState(state);
700
+ const [currentProgress, setCurrentProgress] = React7.useState(progress);
701
+ const fileInputRef = React7.useRef(null);
702
+ const [selectedFiles, setSelectedFiles] = React7.useState([]);
703
+ React7.useEffect(() => {
684
704
  if (loading) {
685
705
  setCurrentState("uploading" /* Uploading */);
686
706
  } else {
687
707
  setCurrentState(state);
688
708
  }
689
709
  }, [state, loading]);
690
- React6.useEffect(() => {
710
+ React7.useEffect(() => {
691
711
  if (loading || progress !== void 0) {
692
712
  setCurrentProgress(progress);
693
713
  }
694
714
  }, [progress, loading]);
695
- const uploadFile = React6.useCallback(
715
+ const uploadFile = React7.useCallback(
696
716
  (file) => {
697
717
  if (!endpoint) {
698
718
  console.warn("Upload endpoint not provided");
@@ -842,10 +862,10 @@ var Upload = React6.forwardRef(
842
862
  style: { gap: "32px" },
843
863
  children: [
844
864
  /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
845
- /* @__PURE__ */ jsx6(Typography, { variant: "heading-sm", children: "Upload fail" }),
846
- /* @__PURE__ */ jsx6(Typography, { variant: "body-md", className: "text-error", children: errorMessage })
865
+ /* @__PURE__ */ jsx7(Typography, { variant: "heading-sm", children: "Upload fail" }),
866
+ /* @__PURE__ */ jsx7(Typography, { variant: "body-md", className: "text-error", children: errorMessage })
847
867
  ] }),
848
- /* @__PURE__ */ jsx6(
868
+ /* @__PURE__ */ jsx7(
849
869
  Button,
850
870
  {
851
871
  variant: "destructive",
@@ -865,9 +885,9 @@ var Upload = React6.forwardRef(
865
885
  className: "flex flex-col items-center text-center max-w-[289px]",
866
886
  style: { gap: "32px" },
867
887
  children: [
868
- /* @__PURE__ */ jsx6(Typography, { variant: "heading-sm", className: "text-dark", children: "Uploading files" }),
888
+ /* @__PURE__ */ jsx7(Typography, { variant: "heading-sm", className: "text-dark", children: "Uploading files" }),
869
889
  /* @__PURE__ */ jsxs4("div", { className: "w-full max-w-[720px] space-y-2", children: [
870
- /* @__PURE__ */ jsx6("div", { className: "w-full bg-canvas-gray rounded-full h-2", children: /* @__PURE__ */ jsx6(
890
+ /* @__PURE__ */ jsx7("div", { className: "w-full bg-canvas-gray rounded-full h-2", children: /* @__PURE__ */ jsx7(
871
891
  "div",
872
892
  {
873
893
  className: "bg-canvas-primary h-2 rounded-full transition-all duration-300 ease-in-out",
@@ -890,14 +910,14 @@ var Upload = React6.forwardRef(
890
910
  }
891
911
  );
892
912
  case "success" /* Success */:
893
- return /* @__PURE__ */ jsx6(
913
+ return /* @__PURE__ */ jsx7(
894
914
  "div",
895
915
  {
896
916
  className: "flex flex-col items-center text-center max-w-[289px]",
897
917
  style: { gap: "32px" },
898
918
  children: /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
899
- /* @__PURE__ */ jsx6(Typography, { variant: "heading-sm", className: "text-success", children: "Upload successful!" }),
900
- selectedFiles.length > 0 && /* @__PURE__ */ jsx6("div", { className: "text-center", children: selectedFiles.map((file, index) => /* @__PURE__ */ jsx6(Typography, { variant: "body-sm", children: file.name }, index)) })
919
+ /* @__PURE__ */ jsx7(Typography, { variant: "heading-sm", className: "text-success", children: "Upload successful!" }),
920
+ selectedFiles.length > 0 && /* @__PURE__ */ jsx7("div", { className: "text-center", children: selectedFiles.map((file, index) => /* @__PURE__ */ jsx7(Typography, { variant: "body-sm", children: file.name }, index)) })
901
921
  ] })
902
922
  }
903
923
  );
@@ -909,10 +929,10 @@ var Upload = React6.forwardRef(
909
929
  style: { gap: "32px" },
910
930
  children: [
911
931
  /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
912
- /* @__PURE__ */ jsx6(Typography, { variant: "heading-sm", className: "text-dark", children: "Drag & drop files here" }),
913
- /* @__PURE__ */ jsx6(Typography, { variant: "body-md", className: "text-secondary", children: "or click to browse from your computer" })
932
+ /* @__PURE__ */ jsx7(Typography, { variant: "heading-sm", className: "text-dark", children: "Drag & drop files here" }),
933
+ /* @__PURE__ */ jsx7(Typography, { variant: "body-md", className: "text-secondary", children: "or click to browse from your computer" })
914
934
  ] }),
915
- /* @__PURE__ */ jsx6(
935
+ /* @__PURE__ */ jsx7(
916
936
  Button,
917
937
  {
918
938
  variant: "default",
@@ -929,7 +949,7 @@ var Upload = React6.forwardRef(
929
949
  /* @__PURE__ */ jsxs4(Typography, { variant: "body-sm", className: "text-secondary", children: [
930
950
  "Supported file: ",
931
951
  getFileTypeDisplay(),
932
- /* @__PURE__ */ jsx6("br", {}),
952
+ /* @__PURE__ */ jsx7("br", {}),
933
953
  "Max: ",
934
954
  Math.round(maxFileSize / 1024 / 1024),
935
955
  " MB each"
@@ -963,7 +983,7 @@ var Upload = React6.forwardRef(
963
983
  "aria-disabled": disabled,
964
984
  ...props,
965
985
  children: [
966
- /* @__PURE__ */ jsx6(
986
+ /* @__PURE__ */ jsx7(
967
987
  "input",
968
988
  {
969
989
  ref: fileInputRef,
@@ -983,11 +1003,11 @@ var Upload = React6.forwardRef(
983
1003
  Upload.displayName = "Upload";
984
1004
 
985
1005
  // src/components/ui/input.tsx
986
- import * as React7 from "react";
987
- import { cva as cva7 } from "class-variance-authority";
1006
+ import * as React8 from "react";
1007
+ import { cva as cva8 } from "class-variance-authority";
988
1008
  import { X, Lock } from "lucide-react";
989
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
990
- var inputVariants = cva7(
1009
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1010
+ var inputVariants = cva8(
991
1011
  "flex w-full border bg-canvas-light text-dark focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:border-edge-default transition-colors rounded-md px-4 py-2 min-w-80 border-edge-default focus-visible:border-2 focus-visible:border-edge-strong placeholder:text-secondary read-only:bg-canvas-gray read-only:cursor-default read-only:border-transparent read-only:text-secondary read-only:focus-visible:border-transparent",
992
1012
  {
993
1013
  variants: {
@@ -1001,7 +1021,7 @@ var inputVariants = cva7(
1001
1021
  }
1002
1022
  }
1003
1023
  );
1004
- var Input = React7.forwardRef(
1024
+ var Input = React8.forwardRef(
1005
1025
  ({
1006
1026
  className,
1007
1027
  variant = "input",
@@ -1012,7 +1032,7 @@ var Input = React7.forwardRef(
1012
1032
  readOnly,
1013
1033
  ...props
1014
1034
  }, ref) => {
1015
- const [internalValue, setInternalValue] = React7.useState(value || "");
1035
+ const [internalValue, setInternalValue] = React8.useState(value || "");
1016
1036
  const isControlled = value !== void 0;
1017
1037
  const currentValue = isControlled ? value : internalValue;
1018
1038
  const showClear = currentValue && currentValue.toString().length > 0 && !readOnly;
@@ -1062,7 +1082,7 @@ var Input = React7.forwardRef(
1062
1082
  };
1063
1083
  if (variant === "textarea") {
1064
1084
  return /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
1065
- /* @__PURE__ */ jsx7(
1085
+ /* @__PURE__ */ jsx8(
1066
1086
  "textarea",
1067
1087
  {
1068
1088
  className: cn(
@@ -1078,20 +1098,20 @@ var Input = React7.forwardRef(
1078
1098
  ...props
1079
1099
  }
1080
1100
  ),
1081
- showClear && /* @__PURE__ */ jsx7(
1101
+ showClear && /* @__PURE__ */ jsx8(
1082
1102
  "button",
1083
1103
  {
1084
1104
  type: "button",
1085
1105
  onClick: handleClear,
1086
1106
  className: "absolute right-3 top-3 h-4 w-4 text-secondary hover:text-dark transition-colors",
1087
- children: /* @__PURE__ */ jsx7(X, { className: "h-4 w-4" })
1107
+ children: /* @__PURE__ */ jsx8(X, { className: "h-4 w-4" })
1088
1108
  }
1089
1109
  ),
1090
- showLock && /* @__PURE__ */ jsx7(Lock, { className: "absolute right-3 top-3 h-4 w-4 text-secondary" })
1110
+ showLock && /* @__PURE__ */ jsx8(Lock, { className: "absolute right-3 top-3 h-4 w-4 text-secondary" })
1091
1111
  ] });
1092
1112
  }
1093
1113
  return /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
1094
- /* @__PURE__ */ jsx7(
1114
+ /* @__PURE__ */ jsx8(
1095
1115
  "input",
1096
1116
  {
1097
1117
  className: cn(
@@ -1107,16 +1127,16 @@ var Input = React7.forwardRef(
1107
1127
  ...props
1108
1128
  }
1109
1129
  ),
1110
- showClear && /* @__PURE__ */ jsx7(
1130
+ showClear && /* @__PURE__ */ jsx8(
1111
1131
  "button",
1112
1132
  {
1113
1133
  type: "button",
1114
1134
  onClick: handleClear,
1115
1135
  className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary hover:text-dark transition-colors",
1116
- children: /* @__PURE__ */ jsx7(X, { className: "h-4 w-4" })
1136
+ children: /* @__PURE__ */ jsx8(X, { className: "h-4 w-4" })
1117
1137
  }
1118
1138
  ),
1119
- showLock && /* @__PURE__ */ jsx7(Lock, { className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary" })
1139
+ showLock && /* @__PURE__ */ jsx8(Lock, { className: "absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-secondary" })
1120
1140
  ] });
1121
1141
  }
1122
1142
  );
@@ -1125,6 +1145,7 @@ var TypedInput = Input;
1125
1145
  export {
1126
1146
  Button,
1127
1147
  ButtonSize,
1148
+ Checkbox,
1128
1149
  DatePicker,
1129
1150
  FormField,
1130
1151
  TypedInput as Input,
@@ -1142,6 +1163,7 @@ export {
1142
1163
  Upload,
1143
1164
  UploadState,
1144
1165
  buttonVariants,
1166
+ checkboxVariants,
1145
1167
  datePickerTriggerVariants,
1146
1168
  inputVariants,
1147
1169
  selectTriggerVariants,
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+
5
+ @theme {
6
+ --color-base-white: #ffffff;
7
+ --color-base-black: #161616;
8
+ --color-neutral-100: #ffffff;
9
+ --color-neutral-200: #f5f5f5;
10
+ --color-neutral-300: #dedede;
11
+ --color-neutral-400: #b5b5b5;
12
+ --color-neutral-500: #909090;
13
+ --color-neutral-600: #666666;
14
+ --color-neutral-700: #4a4a4a;
15
+ --color-neutral-800: #2e2e2e;
16
+ --color-neutral-900: #161616;
17
+ --color-blue-100: #f0f5ff;
18
+ --color-blue-200: #d6e4ff;
19
+ --color-blue-300: #adccff;
20
+ --color-blue-400: #618eff;
21
+ --color-blue-500: #2e69ff;
22
+ --color-blue-600: #004dcc;
23
+ --color-blue-700: #003a99;
24
+ --color-blue-800: #002461;
25
+ --color-blue-900: #00173d;
26
+ --color-green-100: #ebf9f4;
27
+ --color-green-200: #b8ead9;
28
+ --color-green-300: #63d0aa;
29
+ --color-green-400: #11a772;
30
+ --color-green-500: #0c7953;
31
+ --color-green-600: #095d3e;
32
+ --color-green-700: #07462f;
33
+ --color-green-800: #053826;
34
+ --color-green-900: #042f20;
35
+ --color-red-100: #fcf2f2;
36
+ --color-red-200: #f4c8c8;
37
+ --color-red-300: #e58080;
38
+ --color-red-400: #dc5151;
39
+ --color-red-500: #c62828;
40
+ --color-red-600: #aa2222;
41
+ --color-red-700: #881b1b;
42
+ --color-red-800: #5e1313;
43
+ --color-red-900: #400d0d;
44
+ --color-yellow-100: #fffbeb;
45
+ --color-yellow-200: #fef3c7;
46
+ --color-yellow-300: #fde68a;
47
+ --color-yellow-400: #facc15;
48
+ --color-yellow-500: #eab308;
49
+ --color-yellow-600: #ca8a04;
50
+ --color-yellow-700: #a16207;
51
+ --color-yellow-800: #78450a;
52
+ --color-yellow-900: #451a03;
53
+ --color-canvas-light: #ffffff;
54
+ --color-canvas-gray: #f5f5f5;
55
+ --color-canvas-dark: #161616;
56
+ --color-canvas-primary: #2e69ff;
57
+ --color-canvas-info: #f0f5ff;
58
+ --color-canvas-success: #ebf9f4;
59
+ --color-canvas-error: #fcf2f2;
60
+ --color-canvas-error-strong: #c62828;
61
+ --color-canvas-warning: #fffbeb;
62
+ --color-edge-default: #666666;
63
+ --color-edge-subtle: #dedede;
64
+ --color-edge-strong: #161616;
65
+ --color-edge-interactive: #2e69ff;
66
+ --color-edge-error: #c62828;
67
+ --color-edge-warning: #a16207;
68
+ --color-dark: #161616;
69
+ --color-light: #ffffff;
70
+ --color-secondary: #666666;
71
+ --color-info: #004dcc;
72
+ --color-link: #2e69ff;
73
+ --color-success: #0c7953;
74
+ --color-error: #c62828;
75
+ --color-warning: #a16207;
76
+ --color-icon-light: #ffffff;
77
+ --color-icon-dark: #161616;
78
+ --color-icon-secondary: #666666;
79
+ --color-icon-error: #c62828;
80
+ --color-icon-warning: #a16207;
81
+ --typography-display-xl: 400 105px/126px Inter;
82
+ --typography-display-lg: 400 94px/112.8px Inter;
83
+ --typography-display-md: 400 66px/79.2px Inter;
84
+ --typography-display-sm: 400 52px/62.4px Inter;
85
+ --typography-heading-xl: 500 46px/55.2px Inter;
86
+ --typography-heading-lg: 600 32px/38.4px Inter;
87
+ --typography-heading-md: 600 26px/31.2px Inter;
88
+ --typography-heading-sm: 600 20px/24px Inter;
89
+ --typography-body-xl: 400 20px/30px Inter;
90
+ --typography-body-lg: 400 18px/27px Inter;
91
+ --typography-body-md: 400 16px/24px Inter;
92
+ --typography-body-sm: 400 14px/21px Inter;
93
+ --typography-body-xs: 400 12px/18px Inter;
94
+ --typography-label-lg-regular: 400 18px/18px Inter;
95
+ --typography-label-lg-bold: 600 18px/18px Inter;
96
+ --typography-label-md-regular: 400 16px/16px Inter;
97
+ --typography-label-md-bold: 600 16px/16px Inter;
98
+ --typography-label-sm-regular: 400 14px/14px Inter;
99
+ --typography-label-sm-bold: 600 14px/14px Inter;
100
+ --typography-label-xs-regular: 400 12px/12px Inter;
101
+ --typography-label-xs-bold: 600 12px/12px Inter;
102
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@northslopetech/altitude-ui",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "private": false,
5
5
  "description": "React UI components for the Altitude design system",
6
6
  "author": "Northslope",
@@ -49,11 +49,12 @@
49
49
  "tailwindcss": "^4.1.11",
50
50
  "tsup": "^8.0.0",
51
51
  "typescript": "5.8.2",
52
+ "@northslopetech/altitude-tokens": "1.0.0",
52
53
  "@repo/eslint-config": "0.0.0",
53
- "@repo/typescript-config": "0.0.0",
54
- "@northslopetech/altitude-tokens": "1.0.0"
54
+ "@repo/typescript-config": "0.0.0"
55
55
  },
56
56
  "dependencies": {
57
+ "@radix-ui/react-checkbox": "^1.3.3",
57
58
  "@radix-ui/react-dropdown-menu": "^2.1.15",
58
59
  "@radix-ui/react-label": "^2.1.7",
59
60
  "@radix-ui/react-popover": "^1.1.15",
@@ -70,7 +71,7 @@
70
71
  },
71
72
  "scripts": {
72
73
  "prebuild": "cd ../altitude-tokens && npm run build",
73
- "build": "tsup src/index.ts --format cjs,esm --dts --external react --external react-dom",
74
+ "build": "tsup src/index.ts --format cjs,esm --dts --external react --external react-dom && cp ../altitude-tokens/dist/tokens.css dist/tokens.css",
74
75
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch --external react --external react-dom --external altitude-tokens",
75
76
  "clean": "rm -rf dist",
76
77
  "lint": "eslint . --max-warnings 0",