@hideyukimori/nene2-ui 0.2.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/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/data/DataTable.d.ts +32 -0
- package/dist/data/DataTable.js +17 -0
- package/dist/data/DataTable.js.map +1 -0
- package/dist/data/DetailList.d.ts +14 -0
- package/dist/data/DetailList.js +9 -0
- package/dist/data/DetailList.js.map +1 -0
- package/dist/data/Pagination.d.ts +26 -0
- package/dist/data/Pagination.js +20 -0
- package/dist/data/Pagination.js.map +1 -0
- package/dist/feedback/Badge.d.ts +14 -0
- package/dist/feedback/Badge.js +18 -0
- package/dist/feedback/Badge.js.map +1 -0
- package/dist/feedback/InlineAlert.d.ts +15 -0
- package/dist/feedback/InlineAlert.js +18 -0
- package/dist/feedback/InlineAlert.js.map +1 -0
- package/dist/feedback/ToastProvider.d.ts +31 -0
- package/dist/feedback/ToastProvider.js +56 -0
- package/dist/feedback/ToastProvider.js.map +1 -0
- package/dist/feedback/toast-context.d.ts +20 -0
- package/dist/feedback/toast-context.js +17 -0
- package/dist/feedback/toast-context.js.map +1 -0
- package/dist/forms/FormField.d.ts +47 -0
- package/dist/forms/FormField.js +25 -0
- package/dist/forms/FormField.js.map +1 -0
- package/dist/forms/field-context.d.ts +54 -0
- package/dist/forms/field-context.js +51 -0
- package/dist/forms/field-context.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/Box.d.ts +20 -0
- package/dist/layout/Box.js +17 -0
- package/dist/layout/Box.js.map +1 -0
- package/dist/layout/Card.d.ts +16 -0
- package/dist/layout/Card.js +13 -0
- package/dist/layout/Card.js.map +1 -0
- package/dist/layout/Grid.d.ts +15 -0
- package/dist/layout/Grid.js +7 -0
- package/dist/layout/Grid.js.map +1 -0
- package/dist/layout/PageHeader.d.ts +7 -0
- package/dist/layout/PageHeader.js +5 -0
- package/dist/layout/PageHeader.js.map +1 -0
- package/dist/layout/Section.d.ts +16 -0
- package/dist/layout/Section.js +14 -0
- package/dist/layout/Section.js.map +1 -0
- package/dist/layout/Stack.d.ts +20 -0
- package/dist/layout/Stack.js +24 -0
- package/dist/layout/Stack.js.map +1 -0
- package/dist/lib/cx.d.ts +12 -0
- package/dist/lib/cx.js +15 -0
- package/dist/lib/cx.js.map +1 -0
- package/dist/lib/source-probe.d.ts +28 -0
- package/dist/lib/source-probe.js +29 -0
- package/dist/lib/source-probe.js.map +1 -0
- package/dist/lib/spacing.d.ts +54 -0
- package/dist/lib/spacing.js +85 -0
- package/dist/lib/spacing.js.map +1 -0
- package/dist/lib/states.d.ts +44 -0
- package/dist/lib/states.js +45 -0
- package/dist/lib/states.js.map +1 -0
- package/dist/overlay/ConfirmDialog.d.ts +24 -0
- package/dist/overlay/ConfirmDialog.js +17 -0
- package/dist/overlay/ConfirmDialog.js.map +1 -0
- package/dist/overlay/Modal.d.ts +24 -0
- package/dist/overlay/Modal.js +47 -0
- package/dist/overlay/Modal.js.map +1 -0
- package/dist/primitives/Button.d.ts +6 -0
- package/dist/primitives/Button.js +13 -0
- package/dist/primitives/Button.js.map +1 -0
- package/dist/primitives/Checkbox.d.ts +14 -0
- package/dist/primitives/Checkbox.js +19 -0
- package/dist/primitives/Checkbox.js.map +1 -0
- package/dist/primitives/Icon.d.ts +38 -0
- package/dist/primitives/Icon.js +38 -0
- package/dist/primitives/Icon.js.map +1 -0
- package/dist/primitives/Input.d.ts +7 -0
- package/dist/primitives/Input.js +15 -0
- package/dist/primitives/Input.js.map +1 -0
- package/dist/primitives/Radio.d.ts +19 -0
- package/dist/primitives/Radio.js +20 -0
- package/dist/primitives/Radio.js.map +1 -0
- package/dist/primitives/Select.d.ts +9 -0
- package/dist/primitives/Select.js +15 -0
- package/dist/primitives/Select.js.map +1 -0
- package/dist/primitives/Spinner.d.ts +5 -0
- package/dist/primitives/Spinner.js +5 -0
- package/dist/primitives/Spinner.js.map +1 -0
- package/dist/primitives/Switch.d.ts +19 -0
- package/dist/primitives/Switch.js +19 -0
- package/dist/primitives/Switch.js.map +1 -0
- package/dist/primitives/Text.d.ts +7 -0
- package/dist/primitives/Text.js +6 -0
- package/dist/primitives/Text.js.map +1 -0
- package/dist/primitives/Textarea.d.ts +11 -0
- package/dist/primitives/Textarea.js +19 -0
- package/dist/primitives/Textarea.js.map +1 -0
- package/dist/states/EmptyState.d.ts +5 -0
- package/dist/states/EmptyState.js +5 -0
- package/dist/states/EmptyState.js.map +1 -0
- package/dist/states/ErrorState.d.ts +8 -0
- package/dist/states/ErrorState.js +6 -0
- package/dist/states/ErrorState.js.map +1 -0
- package/dist/states/LoadingState.d.ts +18 -0
- package/dist/states/LoadingState.js +19 -0
- package/dist/states/LoadingState.js.map +1 -0
- package/dist/theme/tokens.d.ts +19 -0
- package/dist/theme/tokens.js +20 -0
- package/dist/theme/tokens.js.map +1 -0
- package/package.json +41 -0
- package/themes/default.css +60 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { FieldContext } from './field-context.js';
|
|
4
|
+
/**
|
|
5
|
+
* Labelled form field wrapper: associates a `<label>` with its control, and links the
|
|
6
|
+
* control to its help text and its validation error.
|
|
7
|
+
*
|
|
8
|
+
* 🔴 The control no longer has to opt in. v0.1 documented that the control was "responsible
|
|
9
|
+
* for setting `aria-describedby`", and the fleet did not do it — nene-vault sets
|
|
10
|
+
* `aria-invalid` on 3 fields and links the reason zero times (measured 2026-08-23; see
|
|
11
|
+
* field-context.ts for how that number differs from a raw grep). A field's own error message
|
|
12
|
+
* is the field's job, so `FormField` publishes the ids through context and the kit's controls
|
|
13
|
+
* read them. A control from outside the kit still works; it simply gets the label association
|
|
14
|
+
* it always had.
|
|
15
|
+
*
|
|
16
|
+
* 🔴 The hint stays visible when there is an error. nene-profile hides it in that case, and
|
|
17
|
+
* that is the moment the user most needs it; the error is read first instead.
|
|
18
|
+
*/
|
|
19
|
+
export function FormField({ id, label, error = null, hint, labelAdornment, required = false, requiredMarker, children, }) {
|
|
20
|
+
const errorId = error === null ? null : `${id}-error`;
|
|
21
|
+
const hintId = hint === undefined || hint === null ? null : `${id}-hint`;
|
|
22
|
+
const value = useMemo(() => ({ id, errorId, hintId, required }), [id, errorId, hintId, required]);
|
|
23
|
+
return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: "flex flex-col gap-x-inline-sm", children: [_jsxs("label", { htmlFor: id, className: "font-sans font-medium text-text-primary", children: [label, required && requiredMarker !== undefined && requiredMarker !== null ? (_jsx("span", { className: "text-danger", children: requiredMarker })) : null, labelAdornment] }), children, hintId === null ? null : (_jsx("span", { id: hintId, className: "font-sans text-text-muted", children: hint })), errorId === null ? null : (_jsx("p", { id: errorId, role: "alert", className: "font-sans text-danger", children: error }))] }) }));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=FormField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormField.js","sourceRoot":"","sources":["../../src/forms/FormField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiClD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,GAAG,IAAI,EACZ,IAAI,EACJ,cAAc,EACd,QAAQ,GAAG,KAAK,EAChB,cAAc,EACd,QAAQ,GACO;IACf,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAElG,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,eAAK,SAAS,EAAC,+BAA+B,aAC5C,iBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,yCAAyC,aACpE,KAAK,EACL,QAAQ,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,CACrE,eAAM,SAAS,EAAC,aAAa,YAAE,cAAc,GAAQ,CACtD,CAAC,CAAC,CAAC,IAAI,EACP,cAAc,IACT,EACP,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAC,2BAA2B,YACpD,IAAI,GACA,CACR,EACA,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,YAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,uBAAuB,YAC3D,KAAK,GACJ,CACL,IACG,GACgB,CACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type AriaAttributes } from 'react';
|
|
2
|
+
export interface FieldContextValue {
|
|
3
|
+
/** id the label points at, and the control must carry. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** id of the rendered error message, or null when the field is valid. */
|
|
6
|
+
errorId: string | null;
|
|
7
|
+
/** id of the rendered hint, or null when there is no hint. */
|
|
8
|
+
hintId: string | null;
|
|
9
|
+
/** Whether the field must be filled in. */
|
|
10
|
+
required: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const FieldContext: import("react").Context<FieldContextValue | null>;
|
|
13
|
+
export interface FieldWiring {
|
|
14
|
+
id?: string | undefined;
|
|
15
|
+
'aria-invalid'?: AriaAttributes['aria-invalid'] | undefined;
|
|
16
|
+
'aria-describedby'?: string | undefined;
|
|
17
|
+
'aria-required'?: AriaAttributes['aria-required'] | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Wire a control to the `FormField` around it.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 Why this is not the caller's job, though v0.1 said it was. `FormField` used to carry
|
|
23
|
+
* this in a doc comment:
|
|
24
|
+
*
|
|
25
|
+
* > The control is responsible for setting aria-describedby={`${id}-error`} when it
|
|
26
|
+
* > renders an error
|
|
27
|
+
*
|
|
28
|
+
* Measured across the fleet on 2026-08-23, that delegation did not hold. nene-vault — the
|
|
29
|
+
* first ship scheduled for migration — sets `aria-invalid` on **3 fields** and links the
|
|
30
|
+
* reason **zero times**: assistive technology is told the field is wrong and never told
|
|
31
|
+
* why. nene-payout sets it on 26 fields and links the reason zero times as well.
|
|
32
|
+
*
|
|
33
|
+
* (Counted as JSX props only. A plain `grep -r aria-invalid` over nene-vault's frontend
|
|
34
|
+
* returns 14, not 3: the other eleven are 8 test assertions, 2 comment lines and 1 Tailwind
|
|
35
|
+
* `aria-invalid:` variant selector. Likewise nene-payout's single `aria-describedby` hit is
|
|
36
|
+
* a comment, so its real count is zero, not one. Both of those wrong numbers reached a draft
|
|
37
|
+
* of this comment — written down here so the next person to recount lands on the same one.)
|
|
38
|
+
*
|
|
39
|
+
* 🔴 The same is true of hints. nene-invoice, nene-vault and nene-profile each render one,
|
|
40
|
+
* and none of the three links it — so the help text is visible and never read out. The kit
|
|
41
|
+
* puts both ids on the control, the error first, because once a field is wrong the reason
|
|
42
|
+
* matters more than the advice.
|
|
43
|
+
*
|
|
44
|
+
* A contract a component states in prose and leaves to its callers is a contract that will
|
|
45
|
+
* be half-kept. The kit knows the ids, so the kit does the wiring.
|
|
46
|
+
*
|
|
47
|
+
* Explicit props always win — a caller with its own error region can still say so.
|
|
48
|
+
*/
|
|
49
|
+
export declare function useFieldWiring(explicit: {
|
|
50
|
+
id?: string | undefined;
|
|
51
|
+
ariaInvalid?: AriaAttributes['aria-invalid'] | undefined;
|
|
52
|
+
ariaDescribedBy?: string | undefined;
|
|
53
|
+
ariaRequired?: AriaAttributes['aria-required'] | undefined;
|
|
54
|
+
}): FieldWiring;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const FieldContext = createContext(null);
|
|
3
|
+
/**
|
|
4
|
+
* Wire a control to the `FormField` around it.
|
|
5
|
+
*
|
|
6
|
+
* 🔴 Why this is not the caller's job, though v0.1 said it was. `FormField` used to carry
|
|
7
|
+
* this in a doc comment:
|
|
8
|
+
*
|
|
9
|
+
* > The control is responsible for setting aria-describedby={`${id}-error`} when it
|
|
10
|
+
* > renders an error
|
|
11
|
+
*
|
|
12
|
+
* Measured across the fleet on 2026-08-23, that delegation did not hold. nene-vault — the
|
|
13
|
+
* first ship scheduled for migration — sets `aria-invalid` on **3 fields** and links the
|
|
14
|
+
* reason **zero times**: assistive technology is told the field is wrong and never told
|
|
15
|
+
* why. nene-payout sets it on 26 fields and links the reason zero times as well.
|
|
16
|
+
*
|
|
17
|
+
* (Counted as JSX props only. A plain `grep -r aria-invalid` over nene-vault's frontend
|
|
18
|
+
* returns 14, not 3: the other eleven are 8 test assertions, 2 comment lines and 1 Tailwind
|
|
19
|
+
* `aria-invalid:` variant selector. Likewise nene-payout's single `aria-describedby` hit is
|
|
20
|
+
* a comment, so its real count is zero, not one. Both of those wrong numbers reached a draft
|
|
21
|
+
* of this comment — written down here so the next person to recount lands on the same one.)
|
|
22
|
+
*
|
|
23
|
+
* 🔴 The same is true of hints. nene-invoice, nene-vault and nene-profile each render one,
|
|
24
|
+
* and none of the three links it — so the help text is visible and never read out. The kit
|
|
25
|
+
* puts both ids on the control, the error first, because once a field is wrong the reason
|
|
26
|
+
* matters more than the advice.
|
|
27
|
+
*
|
|
28
|
+
* A contract a component states in prose and leaves to its callers is a contract that will
|
|
29
|
+
* be half-kept. The kit knows the ids, so the kit does the wiring.
|
|
30
|
+
*
|
|
31
|
+
* Explicit props always win — a caller with its own error region can still say so.
|
|
32
|
+
*/
|
|
33
|
+
export function useFieldWiring(explicit) {
|
|
34
|
+
const field = useContext(FieldContext);
|
|
35
|
+
if (field === null) {
|
|
36
|
+
return {
|
|
37
|
+
id: explicit.id,
|
|
38
|
+
'aria-invalid': explicit.ariaInvalid,
|
|
39
|
+
'aria-describedby': explicit.ariaDescribedBy,
|
|
40
|
+
'aria-required': explicit.ariaRequired,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const described = [field.errorId, field.hintId].filter((v) => v !== null).join(' ');
|
|
44
|
+
return {
|
|
45
|
+
id: explicit.id ?? field.id,
|
|
46
|
+
'aria-invalid': explicit.ariaInvalid ?? (field.errorId === null ? undefined : true),
|
|
47
|
+
'aria-describedby': explicit.ariaDescribedBy ?? (described === '' ? undefined : described),
|
|
48
|
+
'aria-required': explicit.ariaRequired ?? (field.required ? true : undefined),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=field-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-context.js","sourceRoot":"","sources":["../../src/forms/field-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAuB,MAAM,OAAO,CAAC;AAavE,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAA2B,IAAI,CAAC,CAAC;AAW1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,cAAc,CAAC,QAK9B;IACC,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAEvC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO;YACL,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,cAAc,EAAE,QAAQ,CAAC,WAAW;YACpC,kBAAkB,EAAE,QAAQ,CAAC,eAAe;YAC5C,eAAe,EAAE,QAAQ,CAAC,YAAY;SACvC,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEjG,OAAO;QACL,EAAE,EAAE,QAAQ,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE;QAC3B,cAAc,EAAE,QAAQ,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACnF,kBAAkB,EAAE,QAAQ,CAAC,eAAe,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,eAAe,EAAE,QAAQ,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;KAC9E,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export { Button, type ButtonProps } from './primitives/Button.js';
|
|
2
|
+
export { Input, type InputProps } from './primitives/Input.js';
|
|
3
|
+
export { Select, type SelectProps } from './primitives/Select.js';
|
|
4
|
+
export { Spinner, type SpinnerProps } from './primitives/Spinner.js';
|
|
5
|
+
export { Text, type TextProps } from './primitives/Text.js';
|
|
6
|
+
export { Textarea, type TextareaProps } from './primitives/Textarea.js';
|
|
7
|
+
export { Icon, type IconProps } from './primitives/Icon.js';
|
|
8
|
+
export { Checkbox, type CheckboxProps } from './primitives/Checkbox.js';
|
|
9
|
+
export { Radio, type RadioProps } from './primitives/Radio.js';
|
|
10
|
+
export { Switch, type SwitchProps } from './primitives/Switch.js';
|
|
11
|
+
export { PageHeader, type PageHeaderProps } from './layout/PageHeader.js';
|
|
12
|
+
export { Stack, type StackProps } from './layout/Stack.js';
|
|
13
|
+
export { Grid, type GridProps } from './layout/Grid.js';
|
|
14
|
+
export { Box, type BoxProps } from './layout/Box.js';
|
|
15
|
+
export { Section, type SectionProps } from './layout/Section.js';
|
|
16
|
+
export { Card, type CardProps } from './layout/Card.js';
|
|
17
|
+
export type { Space, Responsive } from './lib/spacing.js';
|
|
18
|
+
export { FormField, type FormFieldProps } from './forms/FormField.js';
|
|
19
|
+
export { LoadingState, type LoadingStateProps } from './states/LoadingState.js';
|
|
20
|
+
export { EmptyState, type EmptyStateProps } from './states/EmptyState.js';
|
|
21
|
+
export { ErrorState, type ErrorStateProps } from './states/ErrorState.js';
|
|
22
|
+
export { Modal, type ModalProps } from './overlay/Modal.js';
|
|
23
|
+
export { ConfirmDialog, type ConfirmDialogProps } from './overlay/ConfirmDialog.js';
|
|
24
|
+
export { Badge, type BadgeProps } from './feedback/Badge.js';
|
|
25
|
+
export { InlineAlert, type InlineAlertProps } from './feedback/InlineAlert.js';
|
|
26
|
+
export { ToastProvider, type ToastProviderProps } from './feedback/ToastProvider.js';
|
|
27
|
+
export { useToast, type ToastApi, type ToastOptions, type ToastTone, } from './feedback/toast-context.js';
|
|
28
|
+
export { DetailList, type DetailListProps, type DetailRow } from './data/DetailList.js';
|
|
29
|
+
export { DataTable, type DataTableProps, type DataColumn } from './data/DataTable.js';
|
|
30
|
+
export { Pagination, type PaginationProps } from './data/Pagination.js';
|
|
31
|
+
export { tokens } from './theme/tokens.js';
|
|
32
|
+
export { cx } from './lib/cx.js';
|
|
33
|
+
export { CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS } from './lib/states.js';
|
|
34
|
+
export { SOURCE_PROBE_CLASS } from './lib/source-probe.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Primitives
|
|
2
|
+
export { Button } from './primitives/Button.js';
|
|
3
|
+
export { Input } from './primitives/Input.js';
|
|
4
|
+
export { Select } from './primitives/Select.js';
|
|
5
|
+
export { Spinner } from './primitives/Spinner.js';
|
|
6
|
+
export { Text } from './primitives/Text.js';
|
|
7
|
+
export { Textarea } from './primitives/Textarea.js';
|
|
8
|
+
export { Icon } from './primitives/Icon.js';
|
|
9
|
+
export { Checkbox } from './primitives/Checkbox.js';
|
|
10
|
+
export { Radio } from './primitives/Radio.js';
|
|
11
|
+
export { Switch } from './primitives/Switch.js';
|
|
12
|
+
// Layout
|
|
13
|
+
export { PageHeader } from './layout/PageHeader.js';
|
|
14
|
+
export { Stack } from './layout/Stack.js';
|
|
15
|
+
export { Grid } from './layout/Grid.js';
|
|
16
|
+
export { Box } from './layout/Box.js';
|
|
17
|
+
export { Section } from './layout/Section.js';
|
|
18
|
+
export { Card } from './layout/Card.js';
|
|
19
|
+
// Forms
|
|
20
|
+
export { FormField } from './forms/FormField.js';
|
|
21
|
+
// States — the three ship together (design principle 5). Adding a fourth screen state
|
|
22
|
+
// means adding it here, or the set stops being a set.
|
|
23
|
+
export { LoadingState } from './states/LoadingState.js';
|
|
24
|
+
export { EmptyState } from './states/EmptyState.js';
|
|
25
|
+
export { ErrorState } from './states/ErrorState.js';
|
|
26
|
+
// Overlay
|
|
27
|
+
export { Modal } from './overlay/Modal.js';
|
|
28
|
+
export { ConfirmDialog } from './overlay/ConfirmDialog.js';
|
|
29
|
+
// Feedback
|
|
30
|
+
export { Badge } from './feedback/Badge.js';
|
|
31
|
+
export { InlineAlert } from './feedback/InlineAlert.js';
|
|
32
|
+
export { ToastProvider } from './feedback/ToastProvider.js';
|
|
33
|
+
export { useToast, } from './feedback/toast-context.js';
|
|
34
|
+
// Data
|
|
35
|
+
export { DetailList } from './data/DetailList.js';
|
|
36
|
+
export { DataTable } from './data/DataTable.js';
|
|
37
|
+
export { Pagination } from './data/Pagination.js';
|
|
38
|
+
// Theme
|
|
39
|
+
export { tokens } from './theme/tokens.js';
|
|
40
|
+
// Internal helpers, exported so downstream components can compose consistently.
|
|
41
|
+
export { cx } from './lib/cx.js';
|
|
42
|
+
// Controls the kit does not ship yet (Textarea has 7 independent implementations in the
|
|
43
|
+
// fleet) can at least carry the same focus and disabled behaviour instead of inventing it.
|
|
44
|
+
export { CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS } from './lib/states.js';
|
|
45
|
+
// Lets a consumer's build prove the kit is in its Tailwind `@source` (#316).
|
|
46
|
+
export { SOURCE_PROBE_CLASS } from './lib/source-probe.js';
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAqB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAElE,SAAS;AACT,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAqB,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAKxD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAuB,MAAM,sBAAsB,CAAC;AAEtE,sFAAsF;AACtF,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAA0B,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA2B,MAAM,4BAA4B,CAAC;AAEpF,WAAW;AACX,OAAO,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAyB,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAA2B,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,QAAQ,GAIT,MAAM,6BAA6B,CAAC;AAErC,OAAO;AACP,OAAO,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAwB,MAAM,sBAAsB,CAAC;AAExE,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,gFAAgF;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,wFAAwF;AACxF,2FAA2F;AAC3F,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,6EAA6E;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type Responsive, type Space } from '../lib/spacing.js';
|
|
3
|
+
export interface BoxProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Padding on all four sides. `padX` / `padY` win over it, the way `px-*` wins over `p-*`. */
|
|
5
|
+
pad?: Responsive<Space>;
|
|
6
|
+
padX?: Responsive<Space>;
|
|
7
|
+
padY?: Responsive<Space>;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A plain block that carries padding from the scale and nothing else.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 There are deliberately no `w` / `h` props, though the fleet writes 241 sizing
|
|
14
|
+
* utilities by hand. Width is usually a fact about one screen's layout rather than a shared
|
|
15
|
+
* design decision, and the measured values say so: 241 uses spread across 76 distinct
|
|
16
|
+
* classes (`w-24`, `w-56`, `min-w-160`, `w-3.75`…). Turning that into a prop would reopen
|
|
17
|
+
* the value channel this kit exists to close, and would absorb almost nothing. Sizing stays
|
|
18
|
+
* in the caller's `className`, where it is at least visible to a linter.
|
|
19
|
+
*/
|
|
20
|
+
export declare function Box({ pad, padX, padY, children, className, ...rest }: BoxProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { PAD, PAD_X, PAD_Y, resolve } from '../lib/spacing.js';
|
|
4
|
+
/**
|
|
5
|
+
* A plain block that carries padding from the scale and nothing else.
|
|
6
|
+
*
|
|
7
|
+
* 🔴 There are deliberately no `w` / `h` props, though the fleet writes 241 sizing
|
|
8
|
+
* utilities by hand. Width is usually a fact about one screen's layout rather than a shared
|
|
9
|
+
* design decision, and the measured values say so: 241 uses spread across 76 distinct
|
|
10
|
+
* classes (`w-24`, `w-56`, `min-w-160`, `w-3.75`…). Turning that into a prop would reopen
|
|
11
|
+
* the value channel this kit exists to close, and would absorb almost nothing. Sizing stays
|
|
12
|
+
* in the caller's `className`, where it is at least visible to a linter.
|
|
13
|
+
*/
|
|
14
|
+
export function Box({ pad, padX, padY, children, className, ...rest }) {
|
|
15
|
+
return (_jsx("div", { className: cx(resolve(pad, PAD), resolve(padX, PAD_X), resolve(padY, PAD_Y), className), ...rest, children: children }));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=Box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Box.js","sourceRoot":"","sources":["../../src/layout/Box.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAU5F;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAY;IAC7E,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,KACnF,IAAI,YAEP,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type Responsive, type Space } from '../lib/spacing.js';
|
|
3
|
+
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
pad?: Responsive<Space>;
|
|
5
|
+
gap?: Responsive<Space>;
|
|
6
|
+
/** Lift the card off the page. Off by default — a page of shadows reads as no shadows. */
|
|
7
|
+
raised?: boolean;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A bounded surface: background, hairline border, corner radius, padding.
|
|
12
|
+
*
|
|
13
|
+
* Surface, border and radius come from the theme and are not props — a card that could be
|
|
14
|
+
* given its own colour would be a `div` with extra steps.
|
|
15
|
+
*/
|
|
16
|
+
export declare function Card({ pad, gap, raised, children, className, ...rest }: CardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { GAP, PAD, resolve } from '../lib/spacing.js';
|
|
4
|
+
/**
|
|
5
|
+
* A bounded surface: background, hairline border, corner radius, padding.
|
|
6
|
+
*
|
|
7
|
+
* Surface, border and radius come from the theme and are not props — a card that could be
|
|
8
|
+
* given its own colour would be a `div` with extra steps.
|
|
9
|
+
*/
|
|
10
|
+
export function Card({ pad = 'sm', gap, raised = false, children, className, ...rest }) {
|
|
11
|
+
return (_jsx("div", { className: cx('flex flex-col bg-surface-raised border border-border rounded-x-md', raised && 'shadow-sm', resolve(pad, PAD), resolve(gap, GAP), className), ...rest, children: children }));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/layout/Card.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAUnF;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC/F,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,mEAAmE,EACnE,MAAM,IAAI,WAAW,EACrB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,SAAS,CACV,KACG,IAAI,YAEP,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type Responsive, type Space } from '../lib/spacing.js';
|
|
3
|
+
export interface GridProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/**
|
|
5
|
+
* Column count, optionally per breakpoint: `cols={{ base: 1, sm: 2 }}`.
|
|
6
|
+
*
|
|
7
|
+
* Responsive is not a nicety here. `sm:grid-cols-2` is the single most common
|
|
8
|
+
* breakpoint-qualified class in the fleet (14 uses); a `Grid` that could not express it
|
|
9
|
+
* would simply not be adopted.
|
|
10
|
+
*/
|
|
11
|
+
cols?: Responsive<number>;
|
|
12
|
+
gap?: Responsive<Space>;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare function Grid({ cols, gap, children, className, ...rest }: GridProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { COLS, GAP, resolve } from '../lib/spacing.js';
|
|
4
|
+
export function Grid({ cols = 1, gap, children, className, ...rest }) {
|
|
5
|
+
return (_jsx("div", { className: cx('grid', resolve(cols, COLS), resolve(gap, GAP), className), ...rest, children: children }));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=Grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Grid.js","sourceRoot":"","sources":["../../src/layout/Grid.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAepF,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC7E,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,KAAM,IAAI,YACpF,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function PageHeader({ title, actions }) {
|
|
3
|
+
return (_jsxs("header", { className: "flex items-center justify-between py-x-stack-md", children: [_jsx("h1", { className: "font-sans font-medium text-text-primary", children: title }), actions] }));
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=PageHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../src/layout/PageHeader.tsx"],"names":[],"mappings":";AAQA,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAmB;IAC5D,OAAO,CACL,kBAAQ,SAAS,EAAC,iDAAiD,aACjE,aAAI,SAAS,EAAC,yCAAyC,YAAE,KAAK,GAAM,EACnE,OAAO,IACD,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type Responsive, type Space } from '../lib/spacing.js';
|
|
3
|
+
export interface SectionProps extends HTMLAttributes<HTMLElement> {
|
|
4
|
+
pad?: Responsive<Space>;
|
|
5
|
+
/** Rhythm between the section's own blocks. */
|
|
6
|
+
gap?: Responsive<Space>;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A titled region of a page: a real `<section>` that stacks its children vertically.
|
|
11
|
+
*
|
|
12
|
+
* The defaults are the fleet's two most-written padding and gap values (`p-4` and `gap-3`
|
|
13
|
+
* measured across 749 hand-written uses), so the common case needs no props at all —
|
|
14
|
+
* which is the only way a shared component actually gets used.
|
|
15
|
+
*/
|
|
16
|
+
export declare function Section({ pad, gap, children, className, ...rest }: SectionProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { GAP, PAD, resolve } from '../lib/spacing.js';
|
|
4
|
+
/**
|
|
5
|
+
* A titled region of a page: a real `<section>` that stacks its children vertically.
|
|
6
|
+
*
|
|
7
|
+
* The defaults are the fleet's two most-written padding and gap values (`p-4` and `gap-3`
|
|
8
|
+
* measured across 749 hand-written uses), so the common case needs no props at all —
|
|
9
|
+
* which is the only way a shared component actually gets used.
|
|
10
|
+
*/
|
|
11
|
+
export function Section({ pad = 'sm', gap = 'xs', children, className, ...rest }) {
|
|
12
|
+
return (_jsx("section", { className: cx('flex flex-col', resolve(pad, PAD), resolve(gap, GAP), className), ...rest, children: children }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=Section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Section.js","sourceRoot":"","sources":["../../src/layout/Section.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AASnF;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAgB;IAC5F,OAAO,CACL,kBACE,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,KAC3E,IAAI,YAEP,QAAQ,GACD,CACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { type Responsive, type Space } from '../lib/spacing.js';
|
|
3
|
+
export interface StackProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Main axis. Vertical by default — the common case, and the one `space-y-*` was used for. */
|
|
5
|
+
direction?: 'vertical' | 'horizontal';
|
|
6
|
+
gap?: Responsive<Space>;
|
|
7
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
8
|
+
justify?: 'start' | 'center' | 'end' | 'between';
|
|
9
|
+
wrap?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Hairline between children.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 This exists to absorb `last:border-b-0` / `last:pb-0` / `first:pt-0`, which the fleet
|
|
14
|
+
* writes 10 times. Those are not screen decisions — they are a list component leaking its
|
|
15
|
+
* seams into the caller. The kit owns the seams instead of taking them as props.
|
|
16
|
+
*/
|
|
17
|
+
divider?: boolean;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
export declare function Stack({ direction, gap, align, justify, wrap, divider, children, className, ...rest }: StackProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from '../lib/cx.js';
|
|
3
|
+
import { GAP, resolve } from '../lib/spacing.js';
|
|
4
|
+
const ALIGN = {
|
|
5
|
+
start: 'items-start',
|
|
6
|
+
center: 'items-center',
|
|
7
|
+
end: 'items-end',
|
|
8
|
+
stretch: 'items-stretch',
|
|
9
|
+
baseline: 'items-baseline',
|
|
10
|
+
};
|
|
11
|
+
const JUSTIFY = {
|
|
12
|
+
start: 'justify-start',
|
|
13
|
+
center: 'justify-center',
|
|
14
|
+
end: 'justify-end',
|
|
15
|
+
between: 'justify-between',
|
|
16
|
+
};
|
|
17
|
+
const DIVIDER = {
|
|
18
|
+
vertical: 'divide-y divide-border',
|
|
19
|
+
horizontal: 'divide-x divide-border',
|
|
20
|
+
};
|
|
21
|
+
export function Stack({ direction = 'vertical', gap, align, justify, wrap = false, divider = false, children, className, ...rest }) {
|
|
22
|
+
return (_jsx("div", { className: cx('flex', direction === 'vertical' ? 'flex-col' : 'flex-row', resolve(gap, GAP), align && ALIGN[align], justify && JUSTIFY[justify], wrap && 'flex-wrap', divider && DIVIDER[direction], className), ...rest, children: children }));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=Stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.js","sourceRoot":"","sources":["../../src/layout/Stack.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAoB9E,MAAM,KAAK,GAAqD;IAC9D,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,cAAc;IACtB,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE,eAAe;IACxB,QAAQ,EAAE,gBAAgB;CAC3B,CAAC;AAEF,MAAM,OAAO,GAAuD;IAClE,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,gBAAgB;IACxB,GAAG,EAAE,aAAa;IAClB,OAAO,EAAE,iBAAiB;CAC3B,CAAC;AAEF,MAAM,OAAO,GAAyD;IACpE,QAAQ,EAAE,wBAAwB;IAClC,UAAU,EAAE,wBAAwB;CACrC,CAAC;AAEF,MAAM,UAAU,KAAK,CAAC,EACpB,SAAS,GAAG,UAAU,EACtB,GAAG,EACH,KAAK,EACL,OAAO,EACP,IAAI,GAAG,KAAK,EACZ,OAAO,GAAG,KAAK,EACf,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACI;IACX,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,MAAM,EACN,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAClD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,EACrB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAC3B,IAAI,IAAI,WAAW,EACnB,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC,EAC7B,SAAS,CACV,KACG,IAAI,YAEP,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
|
package/dist/lib/cx.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge the kit's own classes with a caller-supplied `className`.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why this exists: spreading `{...rest}` after setting `className` lets a caller's
|
|
5
|
+
* className *replace* the component's styling entirely, silently un-theming the element.
|
|
6
|
+
* Every component in this kit must compose through `cx` instead.
|
|
7
|
+
*
|
|
8
|
+
* The caller's classes come last so Tailwind's later-wins cascade lets them override,
|
|
9
|
+
* which is the intended escape hatch (design principle 2). What is not allowed is
|
|
10
|
+
* accepting colour/spacing/radius as *props* — see README "Design principles".
|
|
11
|
+
*/
|
|
12
|
+
export declare function cx(...parts: (string | false | null | undefined)[]): string;
|
package/dist/lib/cx.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge the kit's own classes with a caller-supplied `className`.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why this exists: spreading `{...rest}` after setting `className` lets a caller's
|
|
5
|
+
* className *replace* the component's styling entirely, silently un-theming the element.
|
|
6
|
+
* Every component in this kit must compose through `cx` instead.
|
|
7
|
+
*
|
|
8
|
+
* The caller's classes come last so Tailwind's later-wins cascade lets them override,
|
|
9
|
+
* which is the intended escape hatch (design principle 2). What is not allowed is
|
|
10
|
+
* accepting colour/spacing/radius as *props* — see README "Design principles".
|
|
11
|
+
*/
|
|
12
|
+
export function cx(...parts) {
|
|
13
|
+
return parts.filter((p) => typeof p === 'string' && p.length > 0).join(' ');
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=cx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cx.js","sourceRoot":"","sources":["../../src/lib/cx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,EAAE,CAAC,GAAG,KAA4C;IAChE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A class that exists only inside this package's build output.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why a consumer needs it. Tailwind v4's automatic content detection does not walk
|
|
5
|
+
* `node_modules`, and every class this kit ships lives in `dist/**` — so an app that
|
|
6
|
+
* imports the theme but does not add the kit to its `@source` generates **none** of them.
|
|
7
|
+
* Measured by nene-vault on 2026-08-23 against `origin/main` `e566a83`: the build was
|
|
8
|
+
* green, the types were green, all 275 tests passed, and the CSS was 47.1 KB instead of
|
|
9
|
+
* 58.6 KB with every `gap-*`, `rounded-*`, focus and disabled class missing. The decisive
|
|
10
|
+
* detail is that `p-x-lg` — the same token, written in the app's own tsx — was generated.
|
|
11
|
+
* The difference is only whether the file lives under `node_modules`.
|
|
12
|
+
*
|
|
13
|
+
* Nothing in that failure is visible: jsdom does not compute styles, so a test suite cannot
|
|
14
|
+
* see it, and the symptom on screen is "the kit does not seem to do anything".
|
|
15
|
+
*
|
|
16
|
+
* So the kit ships a sentinel instead of relying on the README being read:
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* import { SOURCE_PROBE_CLASS } from '@hideyukimori/nene2-ui';
|
|
20
|
+
* const css = readFileSync('dist/assets/index.css', 'utf8');
|
|
21
|
+
* if (!css.includes(`.${SOURCE_PROBE_CLASS}`)) {
|
|
22
|
+
* throw new Error('nene2-ui is not in Tailwind @source — its classes were not generated');
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* The utility resolves to `padding: 0px`, so it is inert if anyone ever applies it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SOURCE_PROBE_CLASS = "p-x-source-probe";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A class that exists only inside this package's build output.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Why a consumer needs it. Tailwind v4's automatic content detection does not walk
|
|
5
|
+
* `node_modules`, and every class this kit ships lives in `dist/**` — so an app that
|
|
6
|
+
* imports the theme but does not add the kit to its `@source` generates **none** of them.
|
|
7
|
+
* Measured by nene-vault on 2026-08-23 against `origin/main` `e566a83`: the build was
|
|
8
|
+
* green, the types were green, all 275 tests passed, and the CSS was 47.1 KB instead of
|
|
9
|
+
* 58.6 KB with every `gap-*`, `rounded-*`, focus and disabled class missing. The decisive
|
|
10
|
+
* detail is that `p-x-lg` — the same token, written in the app's own tsx — was generated.
|
|
11
|
+
* The difference is only whether the file lives under `node_modules`.
|
|
12
|
+
*
|
|
13
|
+
* Nothing in that failure is visible: jsdom does not compute styles, so a test suite cannot
|
|
14
|
+
* see it, and the symptom on screen is "the kit does not seem to do anything".
|
|
15
|
+
*
|
|
16
|
+
* So the kit ships a sentinel instead of relying on the README being read:
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* import { SOURCE_PROBE_CLASS } from '@hideyukimori/nene2-ui';
|
|
20
|
+
* const css = readFileSync('dist/assets/index.css', 'utf8');
|
|
21
|
+
* if (!css.includes(`.${SOURCE_PROBE_CLASS}`)) {
|
|
22
|
+
* throw new Error('nene2-ui is not in Tailwind @source — its classes were not generated');
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* The utility resolves to `padding: 0px`, so it is inert if anyone ever applies it.
|
|
27
|
+
*/
|
|
28
|
+
export const SOURCE_PROBE_CLASS = 'p-x-source-probe';
|
|
29
|
+
//# sourceMappingURL=source-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-probe.js","sourceRoot":"","sources":["../../src/lib/source-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit's spacing scale — the single set of spacing values a caller may choose from.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 Design principle 3: components take no spacing *values*, only names from this scale.
|
|
5
|
+
* `<Stack gap={4.5}>` does not exist, on purpose. Once a number can be written, it will be
|
|
6
|
+
* nudged, and the fleet is back to counting deviations.
|
|
7
|
+
*
|
|
8
|
+
* Why nine steps, and why these nine — measured, not guessed (2026-08-23, #298):
|
|
9
|
+
* across 944 spacing utilities written by hand in the fleet's screens, snapping every one
|
|
10
|
+
* onto this scale moves 98.2% of them by 2px or less, and 99.7% by 4px or less.
|
|
11
|
+
* The fleet currently writes those 944 uses with 153 distinct classes; this is nine.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 Every class below is written out in full. Tailwind finds utilities by scanning source
|
|
14
|
+
* text, so a class assembled at runtime (`gap-x-${size}`) is never generated. Do not
|
|
15
|
+
* "simplify" these tables into template literals — the styles would silently disappear.
|
|
16
|
+
*
|
|
17
|
+
* 🔴 Do not name a step something numeric (`x-2`). `gap-x-2` is Tailwind's own column-gap
|
|
18
|
+
* utility and would win; `gap-x-2xs` is unambiguous because `2xs` is not a number
|
|
19
|
+
* (verified against tailwindcss 4.3.2).
|
|
20
|
+
*/
|
|
21
|
+
export type Space = 'none' | '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
22
|
+
/** Breakpoint-keyed value. Mobile-first: `base` applies until the next key takes over. */
|
|
23
|
+
export type Responsive<T> = T | {
|
|
24
|
+
base?: T;
|
|
25
|
+
sm?: T;
|
|
26
|
+
md?: T;
|
|
27
|
+
lg?: T;
|
|
28
|
+
};
|
|
29
|
+
type ClassSet = {
|
|
30
|
+
base: string;
|
|
31
|
+
sm: string;
|
|
32
|
+
md: string;
|
|
33
|
+
lg: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a responsive prop against one of the tables below.
|
|
37
|
+
* Returns a class string; an undefined value contributes nothing.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolve<T extends string | number>(value: Responsive<T> | undefined, table: Record<string, ClassSet>): string;
|
|
40
|
+
/** `gap` on a flex or grid container. */
|
|
41
|
+
export declare const GAP: Record<Space, ClassSet>;
|
|
42
|
+
/** Padding on all four sides. */
|
|
43
|
+
export declare const PAD: Record<Space, ClassSet>;
|
|
44
|
+
/** Inline (left/right) padding. */
|
|
45
|
+
export declare const PAD_X: Record<Space, ClassSet>;
|
|
46
|
+
/** Block (top/bottom) padding. */
|
|
47
|
+
export declare const PAD_Y: Record<Space, ClassSet>;
|
|
48
|
+
/**
|
|
49
|
+
* Grid column counts. 1–12 rather than only the six the fleet currently uses
|
|
50
|
+
* (1, 2, 3, 4, 5, 7), because a column count is a structural fact about a layout,
|
|
51
|
+
* not a design value — capping it would only push callers back to `grid-cols-*`.
|
|
52
|
+
*/
|
|
53
|
+
export declare const COLS: Record<number, ClassSet>;
|
|
54
|
+
export {};
|