@stamcat/craftsman 0.0.49 → 0.0.51

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamcat/craftsman",
3
- "version": "0.0.49",
3
+ "version": "0.0.51",
4
4
  "type": "module",
5
5
  "description": "A powerful, lightweight framework for design systems",
6
6
  "repository": {
@@ -14,7 +14,7 @@ The package exports an `isEmpty` utility. **Always use it instead of writing inl
14
14
  Import:
15
15
 
16
16
  ```ts
17
- import { isEmpty } from "@stamcat/craftsman/utilities/validations";
17
+ import { isEmpty } from "@stamcat/craftsman/utilities";
18
18
  ```
19
19
 
20
20
  It returns `true` for:
@@ -39,6 +39,18 @@ if (Object.keys(obj).length === 0) { ... }
39
39
  if (arr.length === 0) { ... }
40
40
  ```
41
41
 
42
+ ## Other validation/formatting utilities
43
+
44
+ Also exported from `@stamcat/craftsman/utilities` (all from `src/utilities/validations.ts`):
45
+
46
+ - `validateEmail(value: string): boolean` — simple regex-based email format check.
47
+ - `getUnitLabel(locale, unit, override?): string` — resolves an `Intl.NumberFormat` unit display label, or returns `override` if provided.
48
+ - `is24HourFormat(locale): boolean` — detects whether the locale's resolved hour cycle is 24-hour (`h23`/`h24`).
49
+ - `getAmPmLabels(locale): [string, string]` — returns the locale's AM/PM strings via `Intl.DateTimeFormat`.
50
+ - `formatTime(value, locale): string` — formats a `Date` (or `DateTimePickerProps["value"]`) as a 24-hour `HH:mm` string, or `"--:--"` if not a valid `Date`.
51
+
52
+ These back the `TimePicker`/`DateTimePicker` locale-aware formatting — prefer them over hand-rolled `Intl` calls in those contexts.
53
+
42
54
  ## Style utilities parity (`color`, `width`, `breakpoint`)
43
55
 
44
56
  These utility patterns exist in both TypeScript and Sass. See the [craftsman-style-utilities skill](../craftsman-style-utilities/SKILL.md) for full usage details.
@@ -9,7 +9,7 @@ import { Button } from "@stamcat/craftsman/Button";
9
9
  Props:
10
10
 
11
11
  - Inherits all native `<button>` props.
12
- - `variant?: "primary" | "default" | "text"` (default: `"default"`)
12
+ - `variant?: "primary" | "secondary" | "default" | "text"` (default: `"default"`)
13
13
  - `size?: number` (default visual scale is `1`)
14
14
  - `styles?: React.CSSProperties` (inline style override)
15
15
 
@@ -1,8 +1,6 @@
1
1
  # DateTimePicker — Agent Usage Notes
2
2
 
3
- > Not yet part of the documented public export surface (see `craftsman-component-usage` skill's Known Limitations). Source path only — do not assume `@stamcat/craftsman/DateTimePicker` is published until confirmed in `exports.ts`.
4
-
5
- Import (source-relative, once exported):
3
+ Import:
6
4
 
7
5
  ```tsx
8
6
  import { DateTimePicker } from "@stamcat/craftsman/DateTimePicker";
@@ -13,7 +13,8 @@ Props:
13
13
  - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
14
  - `error?: string | boolean | ReactNode`
15
15
  - `required?: boolean`
16
- - `styles?: React.CSSProperties` (wrapper override)
16
+ - `style?: React.CSSProperties` — targets the wrapper element.
17
+ - `inputStyle?: React.CSSProperties` — targets the `<input>` field directly.
17
18
  - `type?: TextInputType` (checkbox/radio excluded)
18
19
 
19
20
  Behavior notes:
@@ -1 +1 @@
1
- @layer cf-base{.input-pre-adornment,.input-end-adornment{z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .5);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .45);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label,.input-wrapper[data-label-position=inside].select .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] input::placeholder{opacity:0;transition:opacity .2s}.input-field{align-items:center;width:100%;display:flex;position:relative}.input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * 1.5)}.input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) * 2.25)}.input-end-adornment{right:calc(var(--w-gutter) * .5)}.input-pre-adornment{left:calc(var(--w-gutter) * .5)}.input-error{margin-top:calc(var(--w-gutter) * .25);font-size:calc(var(--w-text) * .75);color:var(--red600)}.input-view-toggle{align-items:"center";padding:0;line-height:1;display:inline-flex}}
1
+ @layer cf-base{.input-pre-adornment,.input-end-adornment{z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .5);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .45);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label,.input-wrapper[data-label-position=inside].select .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] input::placeholder{opacity:0;transition:opacity .2s}.input-field{align-items:center;display:flex;position:relative}.input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * 1.5)}.input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) * 2.25)}.input-end-adornment{right:calc(var(--w-gutter) * .5)}.input-pre-adornment{left:calc(var(--w-gutter) * .5)}.input-error{margin-top:calc(var(--w-gutter) * .25);font-size:calc(var(--w-text) * .75);color:var(--red600)}.input-view-toggle{align-items:"center";padding:0;line-height:1;display:inline-flex}}
@@ -6,7 +6,7 @@ import r from "clsx";
6
6
  import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
7
  //#region src/components/Input/Input.tsx
8
8
  var o = (o) => {
9
- let { label: s, id: c, labelPosition: l = "top", required: u = !1, type: d = "text", error: f, endAdornment: p, preAdornment: m, style: h, className: g, value: _, defaultValue: v, ...y } = o, b = n(), x = c || b;
9
+ let { label: s, id: c, labelPosition: l = "top", required: u = !1, type: d = "text", error: f, endAdornment: p, preAdornment: m, style: h, className: g, value: _, defaultValue: v, inputStyle: y, ...b } = o, x = n(), S = c || x;
10
10
  return /* @__PURE__ */ i(t, {
11
11
  className: g,
12
12
  label: s,
@@ -26,12 +26,13 @@ var o = (o) => {
26
26
  children: m
27
27
  }),
28
28
  /* @__PURE__ */ i("input", {
29
- id: x,
29
+ id: S,
30
30
  type: d,
31
31
  className: r("input", d),
32
32
  value: _,
33
33
  defaultValue: v,
34
- ...y
34
+ style: y,
35
+ ...b
35
36
  }),
36
37
  !e(p) && /* @__PURE__ */ i("span", {
37
38
  className: "input-end-adornment",
@@ -146,7 +146,6 @@
146
146
  .input-field {
147
147
  position: relative;
148
148
  display: flex;
149
- width: 100%;
150
149
  align-items: center;
151
150
  &[data-has-end-adornment="true"] {
152
151
  > .input {
@@ -4,6 +4,7 @@ export type LabeledInput = {
4
4
  labelPosition?: LabelPosition;
5
5
  error?: string | boolean | React.ReactNode;
6
6
  required?: boolean;
7
+ inputStyle?: React.CSSProperties;
7
8
  endAdornment?: React.ReactNode;
8
9
  preAdornment?: React.ReactNode;
9
10
  onLabelClick?: React.MouseEventHandler<HTMLLabelElement>;
@@ -9,7 +9,7 @@ import { InputPassword } from "@stamcat/craftsman/InputPassword";
9
9
  Props:
10
10
 
11
11
  - Extends `Input` props, with `type` constrained to password mode.
12
- - Includes all label, error, required, and wrapper style props from `Input`.
12
+ - Includes all label, error, required, and style props from `Input`, including `style` (wrapper) and `inputStyle` (targets the `<input>` field directly).
13
13
 
14
14
  Behavior notes:
15
15
 
@@ -9,6 +9,7 @@ import { InputPhone } from "@stamcat/craftsman/InputPhone";
9
9
  Props:
10
10
 
11
11
  - Extends `PhoneInputProps` from `react-international-phone`.
12
+ - `id?: string` — auto-generated via `useId` if not provided.
12
13
  - `label?: string | ReactNode`
13
14
  - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
15
  - `error?: string | boolean | ReactNode`
@@ -16,6 +17,8 @@ Props:
16
17
  - `defaultCountry?: string` (default: `"us"`)
17
18
  - `preferredCountries?: string[]`
18
19
  - `endAdornment?: ReactNode`
20
+ - `style?: React.CSSProperties` — targets the wrapper element.
21
+ - `inputStyle?: React.CSSProperties` — targets the underlying phone `<input>` field directly.
19
22
 
20
23
  Behavior notes:
21
24
 
@@ -6,10 +6,10 @@ import r from "clsx";
6
6
  import { jsx as i } from "react/jsx-runtime";
7
7
  import { PhoneInput as a } from "react-international-phone";
8
8
  //#region src/components/InputPhone/InputPhone.tsx
9
- var o = ({ label: o, id: s, labelPosition: c = "top", required: l = !1, defaultCountry: u = "us", error: d, style: f, className: p, ...m }) => {
10
- let h = n(), g = s || h, _ = t.useRef(null);
9
+ var o = ({ label: o, id: s, labelPosition: c = "top", required: l = !1, defaultCountry: u = "us", error: d, style: f, className: p, inputStyle: m, ...h }) => {
10
+ let g = n(), _ = s || g, v = t.useRef(null);
11
11
  return /* @__PURE__ */ i(e, {
12
- id: g,
12
+ id: _,
13
13
  className: r("inputPhone", p),
14
14
  label: o,
15
15
  labelPosition: c,
@@ -17,13 +17,14 @@ var o = ({ label: o, id: s, labelPosition: c = "top", required: l = !1, defaultC
17
17
  required: l,
18
18
  style: f,
19
19
  onLabelClick: (e) => {
20
- let t = _.current, n = e.target;
20
+ let t = v.current, n = e.target;
21
21
  !t || n === t || n.closest("button") || (e.preventDefault(), t.focus());
22
22
  },
23
23
  children: /* @__PURE__ */ i(a, {
24
24
  defaultCountry: u,
25
- ...m,
26
- ref: _
25
+ inputStyle: m,
26
+ ...h,
27
+ ref: v
27
28
  })
28
29
  });
29
30
  };
@@ -22,7 +22,7 @@ Props:
22
22
  - `"factory"`
23
23
  - `color?: string` (default: `"black"`)
24
24
  - `width?: number` (optional, variant-dependent default behavior)
25
- - `styles?: React.CSSProperties` (inline style override)
25
+ - `style?: React.CSSProperties` (native inherited style, merged after the computed loader style variables)
26
26
 
27
27
  Example:
28
28
 
@@ -16,7 +16,7 @@ Props:
16
16
  - `backgroundDismiss?: boolean` (default behavior: `true`)
17
17
  - `hideDismissIcon?: boolean` (default behavior: close icon is shown)
18
18
  - `footer?: React.ReactNode`
19
- - `styles?: React.CSSProperties` (applies to outer modal wrapper)
19
+ - `style?: React.CSSProperties` (native inherited style, applies to outer modal wrapper)
20
20
 
21
21
  Behavior notes:
22
22
 
@@ -13,6 +13,8 @@ Props:
13
13
  - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
14
  - `error?: string | boolean | ReactNode`
15
15
  - `required?: boolean`
16
+ - `style?: React.CSSProperties` — targets the wrapper element.
17
+ - `inputStyle?: React.CSSProperties` — targets the `<select>` field directly.
16
18
  - `options?: Array<{ label: string; value: string }>`
17
19
 
18
20
  Behavior notes:
@@ -4,8 +4,8 @@ import { useId as t } from "react";
4
4
  import n from "clsx";
5
5
  import { jsx as r } from "react/jsx-runtime";
6
6
  //#region src/components/Select/Select.tsx
7
- var i = ({ label: i, id: a, labelPosition: o = "top", required: s = !1, error: c, options: l = [], className: u, style: d, ...f }) => {
8
- let p = t(), m = a || p;
7
+ var i = ({ label: i, id: a, labelPosition: o = "top", required: s = !1, error: c, options: l = [], className: u, style: d, inputStyle: f, ...p }) => {
8
+ let m = t(), h = a || m;
9
9
  return /* @__PURE__ */ r(e, {
10
10
  label: i,
11
11
  labelPosition: o,
@@ -14,12 +14,13 @@ var i = ({ label: i, id: a, labelPosition: o = "top", required: s = !1, error: c
14
14
  className: n("select", u),
15
15
  style: d,
16
16
  children: /* @__PURE__ */ r("select", {
17
- id: m,
18
- ...f,
17
+ id: h,
18
+ style: f,
19
+ ...p,
19
20
  children: l.map((e, t) => /* @__PURE__ */ r("option", {
20
21
  value: e.value,
21
22
  children: e.label
22
- }, `${m}-opt-${t}`))
23
+ }, `${h}-opt-${t}`))
23
24
  })
24
25
  });
25
26
  };
@@ -13,6 +13,8 @@ Props:
13
13
  - `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
14
14
  - `error?: string | boolean | ReactNode`
15
15
  - `required?: boolean`
16
+ - `style?: React.CSSProperties` — targets the wrapper element.
17
+ - `inputStyle?: React.CSSProperties` — targets the `<textarea>` field directly.
16
18
  - `rows?: number`
17
19
 
18
20
  Behavior notes:
@@ -3,8 +3,8 @@ import { InputWrapper as e } from "../Input/InputWrapper.esm.js";
3
3
  import { useId as t } from "react";
4
4
  import { jsx as n } from "react/jsx-runtime";
5
5
  //#region src/components/Textarea/Textarea.tsx
6
- var r = ({ labelPosition: r = "top", id: i, label: a, error: o, required: s, className: c, style: l, value: u, defaultValue: d, ...f }) => {
7
- let p = t();
6
+ var r = ({ labelPosition: r = "top", id: i, label: a, error: o, required: s, className: c, style: l, value: u, defaultValue: d, inputStyle: f, ...p }) => {
7
+ let m = t();
8
8
  return /* @__PURE__ */ n(e, {
9
9
  label: a,
10
10
  className: c,
@@ -15,11 +15,12 @@ var r = ({ labelPosition: r = "top", id: i, label: a, error: o, required: s, cla
15
15
  value: u,
16
16
  defaultValue: d,
17
17
  children: /* @__PURE__ */ n("textarea", {
18
- id: i || p,
18
+ id: i || m,
19
19
  className: "input",
20
20
  value: u,
21
21
  defaultValue: d,
22
- ...f
22
+ style: f,
23
+ ...p
23
24
  })
24
25
  });
25
26
  };
@@ -1 +1 @@
1
- @layer cf-base{.react-time-picker__wrapper{color:var(--text);border:1px solid var(--gray400);padding:calc(var(--w-gutter) * .5);background-color:var(--white);border-radius:6px}.react-time-picker__wrapper:focus{box-shadow:none;outline:0}.react-time-picker__wrapper:hover{border-color:var(--gray500)}[type=number].react-time-picker__wrapper::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper{appearance:textfield}.react-time-picker__wrapper:disabled,.disabled.react-time-picker__wrapper{border-color:var(--gray400);background-color:var(--gray100)}}.react-time-picker,.react-time-picker *,.react-time-picker :before,.react-time-picker :after{box-sizing:border-box}@layer cf-component{.react-time-picker{display:inline-flex;position:relative}.react-time-picker--disabled{color:#6d6d6d;background-color:#f0f0f0}.react-time-picker__wrapper{flex-grow:1;flex-shrink:0;padding:6px 8px;display:flex}.react-time-picker__inputGroup{box-sizing:content-box;flex-grow:1;padding:0 2px}.react-time-picker__inputGroup__divider{white-space:pre;padding:1px 0}.react-time-picker__inputGroup__divider,.react-time-picker__inputGroup__leadingZero{font:inherit;display:inline-block}.react-time-picker__inputGroup__input{text-align:center;color:currentColor;min-width:calc(2ch + 1px);height:calc(100% - 2px);font:inherit;box-sizing:content-box;appearance:textfield;background:0 0;border:0;padding:1px;position:relative}[name=year].react-time-picker__inputGroup__input{min-width:calc(4ch + 2px)}.react-time-picker__inputGroup__input:disabled{background-color:unset}.react-time-picker__inputGroup__input::-webkit-outer-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input::-webkit-inner-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input--hasLeadingZero{margin-left:-.54em;padding-left:calc(1px + .54em)}.react-time-picker__button{border:0;padding:4px 4px 4px 7px}.react-time-picker__button:hover{background:0 0}.react-time-picker__wrapper{padding:6px 24px 6px 8px}.react-time-picker__inputGroup__input:invalid{background:#ff00001a}.react-time-picker__inputGroup__amPm{font:inherit;appearance:menulist}.react-time-picker__button:enabled{cursor:pointer}.react-time-picker__button:enabled:hover .react-time-picker__button__icon,.react-time-picker__button:enabled:focus .react-time-picker__button__icon{stroke:#0078d7}.react-time-picker__button:disabled .react-time-picker__button__icon{stroke:#6d6d6d}.react-time-picker__button svg{display:inherit}.react-time-picker__clock{z-index:1;background-color:#fff;border:thin solid #a0a096;width:200px;max-width:100vw;height:200px;padding:25px}.react-time-picker__clock--closed,.timePicker .react-time-picker__clock{display:none}.timePicker .timePicker__field{position:relative}.timePicker .timePicker__field .input-view-toggle{padding:4px;line-height:1;position:absolute;top:50%;right:4px;transform:translateY(-50%)}.timePicker__display{background-color:var(--white);border:1px solid var(--gray400);z-index:1;border-radius:8px;height:160px;display:inline-flex;position:relative}.timePicker__display:before,.timePicker__display:after{content:"";z-index:1;pointer-events:none;height:calc(50% - 16px);display:block;position:absolute;left:0;right:0}.timePicker__display:before{border-bottom:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to top, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);top:-.5px}.timePicker__display:after{border-top:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to bottom, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);bottom:-.5px}.timePicker__display .ios-picker{flex-direction:row;align-items:center;gap:6px;height:100%;padding:0 12px;font-size:16px;line-height:1;display:flex}.timePicker__display .ios-picker--disabled{pointer-events:none;opacity:.5}.timePicker__display .ios-picker__scene{touch-action:pan-x;align-items:center;min-width:30px;height:100%;display:flex;overflow:hidden}.timePicker__display .ios-picker__viewport{perspective:1000px;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-tap-highlight-color:transparent;width:100%;height:32px}.timePicker__display .ios-picker__viewport--perspective-left{perspective-origin:calc(50% + 130px);transform:translate(27px)}.timePicker__display .ios-picker__viewport--perspective-right{perspective-origin:calc(50% - 130px);transform:translate(-27px)}.timePicker__display .ios-picker__viewport--perspective-center{perspective-origin:50%}.timePicker__display .ios-picker__container{width:100%;height:100%;transform-style:preserve-3d;will-change:transform}.timePicker__display .ios-picker__slide{text-align:center;backface-visibility:hidden;opacity:0;justify-content:center;align-items:center;width:100%;height:100%;display:flex}.timePicker__display .ios-picker__label{white-space:nowrap;pointer-events:none;font-weight:700}}
1
+ @layer cf-base{.react-time-picker__wrapper{color:var(--text);border:1px solid var(--gray400);padding:calc(var(--w-gutter) * .5);background-color:var(--white);border-radius:6px}.react-time-picker__wrapper:focus{box-shadow:none;outline:0}.react-time-picker__wrapper:hover{border-color:var(--gray500)}[type=number].react-time-picker__wrapper::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}[type=number].react-time-picker__wrapper{appearance:textfield}.react-time-picker__wrapper:disabled,.disabled.react-time-picker__wrapper{border-color:var(--gray400);background-color:var(--gray100)}}.react-time-picker,.react-time-picker *,.react-time-picker :before,.react-time-picker :after{box-sizing:border-box}@layer cf-component{.react-time-picker{display:inline-flex;position:relative}.react-time-picker--disabled{color:#6d6d6d;background-color:#f0f0f0}.react-time-picker__wrapper{flex-grow:1;flex-shrink:0;padding:6px 8px;display:flex}.react-time-picker__inputGroup{box-sizing:content-box;flex-grow:1;padding:0 2px}.react-time-picker__inputGroup__divider{white-space:pre;padding:1px 0}.react-time-picker__inputGroup__divider,.react-time-picker__inputGroup__leadingZero{font:inherit;display:inline-block}.react-time-picker__inputGroup__input{text-align:center;color:currentColor;min-width:calc(2ch + 1px);height:calc(100% - 2px);font:inherit;box-sizing:content-box;appearance:textfield;background:0 0;border:0;padding:1px;position:relative}[name=year].react-time-picker__inputGroup__input{min-width:calc(4ch + 2px)}.react-time-picker__inputGroup__input:disabled{background-color:unset}.react-time-picker__inputGroup__input::-webkit-outer-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input::-webkit-inner-spin-button{appearance:none;margin:0}.react-time-picker__inputGroup__input--hasLeadingZero{margin-left:-.54em;padding-left:calc(1px + .54em)}.react-time-picker__button{border:0;padding:4px 4px 4px 7px}.react-time-picker__button:hover{background:0 0}.react-time-picker__wrapper{padding:6px 8px}.react-time-picker__inputGroup__input:invalid{background:#ff00001a}.react-time-picker__inputGroup__amPm{font:inherit;appearance:menulist}.react-time-picker__button:enabled{cursor:pointer}.react-time-picker__button:enabled:hover .react-time-picker__button__icon,.react-time-picker__button:enabled:focus .react-time-picker__button__icon{stroke:#0078d7}.react-time-picker__button:disabled .react-time-picker__button__icon{stroke:#6d6d6d}.react-time-picker__button svg{display:inherit}.react-time-picker__clock{z-index:1;background-color:#fff;border:thin solid #a0a096;width:200px;max-width:100vw;height:200px;padding:25px}.react-time-picker__clock--closed,.timePicker .react-time-picker__clock{display:none}.timePicker .timePicker__field{width:fit-content;position:relative}.timePicker .timePicker__field:has(.input-view-toggle) .react-time-picker__wrapper{padding-right:34px}.timePicker .timePicker__field .input-view-toggle{padding:4px;line-height:1;position:absolute;top:50%;right:10px;transform:translateY(-50%)}.timePicker__display{background-color:var(--white);border:1px solid var(--gray400);z-index:1;border-radius:8px;height:160px;display:inline-flex;position:relative}.timePicker__display:before,.timePicker__display:after{content:"";z-index:1;pointer-events:none;height:calc(50% - 16px);display:block;position:absolute;left:0;right:0}.timePicker__display:before{border-bottom:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to top, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);top:-.5px}.timePicker__display:after{border-top:.5px solid rgba(var(--text-high-contrast-rgb-value), .3);background:linear-gradient(to bottom, rgba(var(--background-site-rgb-value), .65) 0%, rgba(var(--background-site-rgb-value), 1) 100%);bottom:-.5px}.timePicker__display .ios-picker{flex-direction:row;align-items:center;gap:6px;height:100%;padding:0 12px;font-size:16px;line-height:1;display:flex}.timePicker__display .ios-picker--disabled{pointer-events:none;opacity:.5}.timePicker__display .ios-picker__scene{touch-action:pan-x;align-items:center;min-width:30px;height:100%;display:flex;overflow:hidden}.timePicker__display .ios-picker__viewport{perspective:1000px;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-tap-highlight-color:transparent;width:100%;height:32px}.timePicker__display .ios-picker__viewport--perspective-left{perspective-origin:calc(50% + 130px);transform:translate(27px)}.timePicker__display .ios-picker__viewport--perspective-right{perspective-origin:calc(50% - 130px);transform:translate(-27px)}.timePicker__display .ios-picker__viewport--perspective-center{perspective-origin:50%}.timePicker__display .ios-picker__container{width:100%;height:100%;transform-style:preserve-3d;will-change:transform}.timePicker__display .ios-picker__slide{text-align:center;backface-visibility:hidden;opacity:0;justify-content:center;align-items:center;width:100%;height:100%;display:flex}.timePicker__display .ios-picker__label{white-space:nowrap;pointer-events:none;font-weight:700}}
@@ -12,7 +12,7 @@ import { TimePicker as g } from "react-time-picker";
12
12
  import { isMobile as _ } from "react-device-detect";
13
13
  //#region src/components/TimePicker/TimePicker.tsx
14
14
  var v = (v) => {
15
- let { labels: y, locale: b, format: x, value: S, onChange: C, label: w, labelPosition: T, error: E, required: D, name: O, ...k } = v, [A, j] = a(null), [M, N] = a(null), { floatingStyles: P } = h({
15
+ let { labels: y, locale: b, format: x, value: S, onChange: C, label: w, labelPosition: T, error: E, required: D, name: O, disableClock: k, ...A } = v, [j, M] = a(null), [N, P] = a(null), { floatingStyles: F } = h({
16
16
  placement: "bottom-start",
17
17
  strategy: "absolute",
18
18
  whileElementsMounted: d,
@@ -22,30 +22,30 @@ var v = (v) => {
22
22
  m()
23
23
  ],
24
24
  elements: {
25
- reference: A,
26
- floating: M
25
+ reference: j,
26
+ floating: N
27
27
  }
28
- }), [F, I] = a(!1), L = n(b);
28
+ }), [I, L] = a(!1), R = n(b);
29
29
  return i(() => {
30
- if (!F) return;
30
+ if (!I) return;
31
31
  let e = (e) => {
32
- A?.contains(e.target) || M?.contains(e.target) || I(!1);
32
+ j?.contains(e.target) || N?.contains(e.target) || L(!1);
33
33
  };
34
34
  return document.addEventListener("pointerdown", e), () => {
35
35
  document.removeEventListener("pointerdown", e);
36
36
  };
37
37
  }, [
38
- F,
39
- A,
40
- M
38
+ I,
39
+ j,
40
+ N
41
41
  ]), /* @__PURE__ */ u("div", {
42
42
  className: "timePicker",
43
- ref: j,
43
+ ref: M,
44
44
  onFocus: (e) => {
45
- _ || e.target instanceof HTMLInputElement && I(!0);
45
+ _ || e.target instanceof HTMLInputElement && L(!0);
46
46
  },
47
47
  onKeyDown: (e) => {
48
- e.key === "Enter" && I(!1);
48
+ e.key === "Enter" && L(!1);
49
49
  },
50
50
  children: [
51
51
  O && /* @__PURE__ */ l("input", {
@@ -62,34 +62,34 @@ var v = (v) => {
62
62
  children: /* @__PURE__ */ u("div", {
63
63
  className: "timePicker__field",
64
64
  children: [/* @__PURE__ */ l(g, {
65
- ...k,
66
65
  value: S,
67
66
  onChange: C,
68
- locale: L,
67
+ locale: R,
69
68
  required: D,
69
+ clearIcon: /* @__PURE__ */ l(c, { size: 14 }),
70
70
  disableClock: !0,
71
- clearIcon: /* @__PURE__ */ l(c, { size: 14 })
72
- }), !_ && /* @__PURE__ */ l(e, {
71
+ ...A
72
+ }), !_ && !k && /* @__PURE__ */ l(e, {
73
73
  type: "button",
74
74
  variant: "text",
75
- onClick: () => I((e) => !e),
76
- "aria-label": F ? "Hide time picker" : "Show time picker",
77
- "aria-pressed": F,
75
+ onClick: () => L((e) => !e),
76
+ "aria-label": I ? "Hide time picker" : "Show time picker",
77
+ "aria-pressed": I,
78
78
  disabled: v.disabled,
79
79
  className: "input-view-toggle",
80
- children: l(F ? o : s, { size: 16 })
80
+ children: l(I ? o : s, { size: 16 })
81
81
  })]
82
82
  })
83
83
  }),
84
- !_ && /* @__PURE__ */ l(r, {
84
+ !_ && !k && /* @__PURE__ */ l(r, {
85
85
  value: S,
86
86
  onChange: (e) => C?.(e),
87
- locale: L,
87
+ locale: R,
88
88
  labels: y,
89
89
  format: x,
90
- visible: F,
91
- floatingRef: N,
92
- style: P
90
+ visible: I,
91
+ floatingRef: P,
92
+ style: F
93
93
  })
94
94
  ]
95
95
  });
@@ -18,7 +18,7 @@
18
18
  }
19
19
  &__wrapper {
20
20
  @extend %date-picker-wrapper;
21
- padding: 6px 24px 6px 8px;
21
+ padding: 6px 8px;
22
22
  }
23
23
  &__inputGroup {
24
24
  @extend %date-picker-input-group;
@@ -95,10 +95,17 @@
95
95
 
96
96
  .timePicker__field {
97
97
  position: relative;
98
+ width: fit-content;
99
+
100
+ &:has(.input-view-toggle) {
101
+ .react-time-picker__wrapper {
102
+ padding-right: 34px;
103
+ }
104
+ }
98
105
 
99
106
  .input-view-toggle {
100
107
  position: absolute;
101
- right: 4px;
108
+ right: 10px;
102
109
  top: 50%;
103
110
  transform: translateY(-50%);
104
111
  padding: 4px;
@@ -1,8 +1,6 @@
1
1
  # Tooltip — Agent Usage Notes
2
2
 
3
- > Not yet part of the documented public export surface (see `craftsman-component-usage` skill's Known Limitations). Source path only — do not assume `@stamcat/craftsman/Tooltip` is published until confirmed in `exports.ts`.
4
-
5
- Import (source-relative, once exported):
3
+ Import:
6
4
 
7
5
  ```tsx
8
6
  import { Tooltip } from "@stamcat/craftsman/Tooltip";