= ({ component, status, note }) => {
+ const rawEntry = component !== undefined ? COMPONENTS[component] : undefined;
+ let entry: ComponentEntry | undefined;
+
+ if (rawEntry === undefined) {
+ entry = undefined;
+ } else if (isComponentEntry(rawEntry)) {
+ entry = rawEntry;
+ } else {
+ warnDev(`Invalid entry for "${component}" in component-status.json.`);
+ entry = undefined;
+ }
+
+ const resolvedStatus = resolveStatus(component, status, entry);
+ const resolvedNote =
+ note ?? (status === undefined && entry !== undefined ? entry.note : undefined);
+ const label = STATUS_LABELS[resolvedStatus];
+ const ariaLabel = buildAriaLabel(label, resolvedNote);
+
+ return (
+
+
+ {label}
+ {resolvedNote !== undefined && resolvedNote !== '' ? (
+ — {resolvedNote}
+ ) : null}
+
+ );
+};
diff --git a/libs/core/src/stories/_helpers/index.ts b/libs/core/src/stories/_helpers/index.ts
index 28e78405e..aa1587b32 100644
--- a/libs/core/src/stories/_helpers/index.ts
+++ b/libs/core/src/stories/_helpers/index.ts
@@ -32,4 +32,6 @@ export const customArgsWithIconControl = ({property}: Omit
+
+# Component status
+
+Lifecycle labels describe **API and visual stability** for product teams—not Storybook polish. They are updated when a component’s contract or usage is intentionally changing.
+
+> **Source of truth:** `libs/core/src/stories/resources/component-status.json` drives both this table and the `StatusBadge` rendered on each component MDX page. When you promote or deprecate a component, edit the JSON manifest **and** the table below in the same PR.
+
+## Definitions
+
+
+
+
+ Label
+ Meaning
+
+
+
+ Stable
+ Safe for broad production use; breaking changes follow semver and migration notes.
+
+
+ Beta
+ API or visuals may still shift; prefer new work here only when you accept occasional churn.
+
+
+ Deprecated
+ Do not use in new UI; plan migration; removal is scheduled with notice in the changelog.
+
+
+
+
+
+## Pine web components
+
+All components below are **Stable** unless noted. Subcomponents (for example `pds-table-row`) follow the parent unless called out separately.
+
+
+
+
+ Component
+ Status
+ Notes
+
+
+
+ pds-accordion
+ Stable
+
+
+
+ pds-alert
+ Stable
+
+
+
+ pds-avatar
+ Stable
+
+
+
+ pds-box
+ Stable
+
+
+
+ pds-button
+ Stable
+
+
+
+ pds-checkbox
+ Stable
+
+
+
+ pds-chip
+ Stable
+
+
+
+ pds-combobox
+ Stable
+
+
+
+ pds-container
+ Stable
+
+
+
+ pds-copytext
+ Stable
+
+
+
+ pds-divider
+ Stable
+
+
+
+ pds-dropdown-menu
+ Stable
+
+
+
+ pds-filters / pds-filter
+ Stable
+
+
+
+ pds-icon
+ Stable
+ Icons ship from @pine-ds/icons.
+
+
+ pds-image
+ Stable
+
+
+
+ pds-input
+ Stable
+
+
+
+ pds-link
+ Stable
+
+
+
+ pds-loader
+ Stable
+
+
+
+ pds-modal
+ Stable
+
+
+
+ pds-multiselect
+ Stable
+
+
+
+ pds-popover
+ Stable
+
+
+
+ pds-progress
+ Stable
+
+
+
+ pds-property
+ Stable
+
+
+
+ pds-radio / pds-radio-group
+ Stable
+
+
+
+ pds-row
+ Stable
+
+
+
+ pds-select
+ Stable
+
+
+
+ pds-sortable
+ Stable
+
+
+
+ pds-switch
+ Stable
+
+
+
+ pds-table
+ Stable
+
+
+
+ pds-tabs
+ Stable
+
+
+
+ pds-text
+ Stable
+
+
+
+ pds-textarea
+ Stable
+
+
+
+ pds-toast
+ Stable
+
+
+
+ pds-tooltip
+ Stable
+
+
+
+
+
+
+When a component moves to **Beta** or **Deprecated**, update this table in the same pull request as the changelog entry and any Storybook migration callouts.
diff --git a/libs/core/src/stories/resources/component-status.json b/libs/core/src/stories/resources/component-status.json
new file mode 100644
index 000000000..7a13fd676
--- /dev/null
+++ b/libs/core/src/stories/resources/component-status.json
@@ -0,0 +1,56 @@
+{
+ "$schema": "./component-status.schema.json",
+ "description": "Lifecycle status for every Pine component. Source of truth for StatusBadge and the central Component status table. Update both when a component is promoted to Beta or Deprecated.",
+ "statuses": {
+ "stable": {
+ "label": "Stable",
+ "summary": "Safe for broad production use; breaking changes follow semver and migration notes."
+ },
+ "beta": {
+ "label": "Beta",
+ "summary": "API or visuals may still shift; prefer new work here only when you accept occasional churn."
+ },
+ "deprecated": {
+ "label": "Deprecated",
+ "summary": "Do not use in new UI; plan migration; removal is scheduled with notice in the changelog."
+ }
+ },
+ "components": {
+ "pds-accordion": { "status": "stable" },
+ "pds-alert": { "status": "stable" },
+ "pds-avatar": { "status": "stable" },
+ "pds-box": { "status": "stable" },
+ "pds-button": { "status": "stable" },
+ "pds-checkbox": { "status": "stable" },
+ "pds-chip": { "status": "stable" },
+ "pds-combobox": { "status": "stable" },
+ "pds-container": { "status": "stable" },
+ "pds-copytext": { "status": "stable" },
+ "pds-divider": { "status": "stable" },
+ "pds-dropdown-menu": { "status": "stable" },
+ "pds-filters": { "status": "stable" },
+ "pds-filter": { "status": "stable", "note": "Subcomponent of pds-filters." },
+ "pds-icon": { "status": "stable", "note": "Icons ship from `@pine-ds/icons`." },
+ "pds-image": { "status": "stable" },
+ "pds-input": { "status": "stable" },
+ "pds-link": { "status": "stable" },
+ "pds-loader": { "status": "stable" },
+ "pds-modal": { "status": "stable" },
+ "pds-multiselect": { "status": "stable" },
+ "pds-popover": { "status": "stable" },
+ "pds-progress": { "status": "stable" },
+ "pds-property": { "status": "stable" },
+ "pds-radio": { "status": "stable" },
+ "pds-radio-group": { "status": "stable" },
+ "pds-row": { "status": "stable" },
+ "pds-select": { "status": "stable" },
+ "pds-sortable": { "status": "stable" },
+ "pds-switch": { "status": "stable" },
+ "pds-table": { "status": "stable" },
+ "pds-tabs": { "status": "stable" },
+ "pds-text": { "status": "stable" },
+ "pds-textarea": { "status": "stable" },
+ "pds-toast": { "status": "stable" },
+ "pds-tooltip": { "status": "stable" }
+ }
+}