Ctrl K
ComunidadGuías…

openapi-nm-design-system.yaml

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
openapi: 3.0.3
info:
  title: NoMercy NM Design System Components
  description: |
    The server-driven component vocabulary, generated from the design system.

    This file is a sibling of `openapi-nm-components.yaml` and follows the same
    rules: an envelope carrying `id`, `component` and `props`, a discriminator on
    `component`, nested children under `items`, and a free-form `properties` bag
    for anything a payload needs to carry that the contract has not named yet.

    What this file adds is the box. Every component here accepts an `NMBox` and
    an `NMSurface`, which is what makes them compose: a parent can place a child
    without the child knowing anything about where it was placed, and a plugin
    can lay out a dashboard entirely from the payload.

    The media-domain components in `openapi-nm-components.yaml` are unchanged.
    They keep their existing shape and their existing clients keep working. The
    versions of those components that adopt this box live here, under the same
    names, and a client opts in by rendering from this vocabulary.

    Nothing here carries a raw CSS value. Every length, colour and radius is a
    token key resolved by the client, which is the only reason the same payload
    can render on a platform that has no CSS.
  version: 1.0.0

components:
  schemas:
    # ===========================================
    # The box
    # ===========================================
    NMBox:
      type: object
      description: |
        Geometry, split by who owns it.

        The outer group is what a parent decides about this component: its
        margin, how it flexes, how it aligns itself, how many columns it spans,
        how big it is. A parent sets these on a child it is placing.

        The inner group is what this component decides about its own children:
        padding, gap, direction, alignment. A component sets these on itself.

        Both groups are optional and both are overridable by the payload. The
        rule that makes this reliable is not in the shape of this object, it is
        in the order the client applies it: a value from the payload is applied
        after the component's own default, so the payload always wins. A client
        that resolves them in the other order will look correct until the first
        time a parent tries to override a child, which is the failure that would
        otherwise ship silently.
      properties:
        # ---- outer: what the parent decides ----
        margin:
          $ref: '#/components/schemas/NMSpacing'
        width:
          $ref: '#/components/schemas/NMSize'
        height:
          $ref: '#/components/schemas/NMSize'
        min_width:
          $ref: '#/components/schemas/NMSize'
        max_width:
          $ref: '#/components/schemas/NMSize'
        min_height:
          $ref: '#/components/schemas/NMSize'
        max_height:
          $ref: '#/components/schemas/NMSize'
        grow:
          type: integer
          nullable: true
          minimum: 0
          description: How much of the leftover space along the parent's axis this takes.
        shrink:
          type: integer
          nullable: true
          minimum: 0
          description: How readily this gives up space when the parent runs short.
        basis:
          $ref: '#/components/schemas/NMSize'
        align_self:
          $ref: '#/components/schemas/NMAlign'
        order:
          type: integer
          nullable: true
          description: Visual position among siblings, independent of payload order.
        column_span:
          type: integer
          nullable: true
          minimum: 1
          description: Columns this occupies when the parent is a grid.
        row_span:
          type: integer
          nullable: true
          minimum: 1
          description: Rows this occupies when the parent is a grid.
        position:
          $ref: '#/components/schemas/NMPosition'
        inset:
          $ref: '#/components/schemas/NMSpacing'
        layer:
          $ref: '#/components/schemas/NMLayer'
        hidden_on:
          type: array
          items:
            $ref: '#/components/schemas/NMSurfaceKind'
          default: []
          description: |
            Surfaces this component is not rendered on at all. A component hidden
            on tv is never focusable there, which is different from a component
            that is merely invisible, and is what D-pad traversal needs.

        # ---- inner: what this component decides ----
        padding:
          $ref: '#/components/schemas/NMSpacing'
        gap:
          $ref: '#/components/schemas/NMGap'
        direction:
          $ref: '#/components/schemas/NMDirection'
        align:
          $ref: '#/components/schemas/NMAlign'
        justify:
          $ref: '#/components/schemas/NMJustify'
        wrap:
          $ref: '#/components/schemas/NMWrap'
        columns:
          type: integer
          nullable: true
          minimum: 1
          description: Fixed column count when this component lays its children out as a grid.
        overflow:
          $ref: '#/components/schemas/NMOverflow'

    NMSpacing:
      type: object
      description: |
        A spacing value, expressed per side. Resolution runs from the most
        general to the most specific: `all`, then `x` and `y`, then a named side.
        A later value replaces an earlier one for the side it names.

        Every value is a key on the spacing scale, not a length. `"4"` means the
        scale's step 4, which the client resolves to its own unit. Writing a
        length here is not supported, because a length cannot survive the trip to
        a platform whose unit is not the one it was written in.
      properties:
        all:
          $ref: '#/components/schemas/NMSpace'
        x:
          $ref: '#/components/schemas/NMSpace'
        y:
          $ref: '#/components/schemas/NMSpace'
        top:
          $ref: '#/components/schemas/NMSpace'
        right:
          $ref: '#/components/schemas/NMSpace'
        bottom:
          $ref: '#/components/schemas/NMSpace'
        left:
          $ref: '#/components/schemas/NMSpace'

    NMGap:
      type: object
      description: |
        The space between children, which can differ along each axis. `all` sets
        both; `x` and `y` override it per axis.
      properties:
        all:
          $ref: '#/components/schemas/NMSpace'
        x:
          $ref: '#/components/schemas/NMSpace'
        y:
          $ref: '#/components/schemas/NMSpace'

    NMSpace:
      type: string
      nullable: true
      description: |
        A key on the spacing scale. The scale is the design system's, so a key
        that is not on it is a payload error rather than something the client
        should try to interpret.
      enum:
        - '0'
        - px
        - '0-5'
        - '1'
        - '1-5'
        - '2'
        - '2-5'
        - '3'
        - '3-5'
        - '4'
        - '4-5'
        - '5'
        - '6'
        - '7'
        - '8'
        - '9'
        - '10'
        - '11'
        - '12'
        - '14'
        - '15'
        - '16'
        - '20'
        - '24'
        - '28'
        - '32'
        - '36'
        - '40'
        - '44'
        - '48'
        - '52'
        - '56'
        - '60'
        - '64'
        - '72'
        - '80'
        - '96'

    NMSize:
      type: string
      nullable: true
      description: |
        A size. Either a key on the spacing scale, a fraction of the parent, or a
        keyword. Fractions are written as they read: `1/2`, `2/3`, `5/6`.

        `content` sizes to what is inside. `available` fills what the parent
        offers. `auto` lets the platform decide, which is the default when the
        field is absent.
      pattern: '^(0|px|\d+(-\d)?|\d+/\d+|auto|full|available|content|min|max|screen)$'

    NMAlign:
      type: string
      nullable: true
      description: Alignment across the axis that runs against the layout direction.
      enum: [start, center, end, stretch, baseline]

    NMJustify:
      type: string
      nullable: true
      description: Distribution along the layout direction.
      enum: [start, center, end, between, around, evenly]

    NMDirection:
      type: string
      nullable: true
      description: |
        The axis children flow along. `row` and `column` are resolved against the
        reading direction, so a right-to-left locale reverses `row` without the
        payload saying anything about it.
      enum: [row, column, row-reverse, column-reverse]

    NMWrap:
      type: string
      nullable: true
      enum: [nowrap, wrap, wrap-reverse]

    NMOverflow:
      type: string
      nullable: true
      description: |
        What happens to children that do not fit. `scroll` on a tv surface means
        the container scrolls to follow focus, since there is no pointer to drag
        it with.
      enum: [visible, hidden, scroll, clip]

    NMPosition:
      type: string
      nullable: true
      enum: [static, relative, absolute, sticky, fixed]

    NMLayer:
      type: string
      nullable: true
      description: |
        Stacking order, named rather than numbered. A payload that could set a
        raw z-index would eventually set one that beats the player chrome, so the
        vocabulary is closed on purpose.
      enum: [base, raised, sticky, overlay, modal, toast, tooltip]

    NMSurfaceKind:
      type: string
      description: A rendering surface, used to vary or suppress a component per platform.
      enum: [web, mobile, tv]

    # ===========================================
    # The skin
    # ===========================================
    NMSurface:
      type: object
      description: |
        Appearance, kept apart from geometry so a component can be re-skinned
        without touching its layout and re-laid-out without touching its skin.

        Colours are token keys, never hex. A payload carrying hex would render
        correctly in one theme and wrongly in the other, and would not respond
        when the user switches.
      properties:
        background:
          $ref: '#/components/schemas/NMColor'
        foreground:
          $ref: '#/components/schemas/NMColor'
        border_color:
          $ref: '#/components/schemas/NMColor'
        border_width:
          type: string
          nullable: true
          enum: ['0', px, '2', '4', '8']
        radius:
          type: string
          nullable: true
          enum: [none, sm, base, md, lg, xl, 2xl, 3xl, full]
        shadow:
          type: string
          nullable: true
          enum: [none, xs, sm, md, lg, xl, 2xl, inner]
        opacity:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
        elevation:
          type: string
          nullable: true
          description: |
            How the component lifts when it takes focus. This is the tv surface's
            equivalent of hover, which does not exist there.
          enum: [none, subtle, raised, floating]

    NMColor:
      type: string
      nullable: true
      description: |
        A colour token key from the design system, without the leading dashes.
        Both a semantic name and a scale step are accepted, so `surface-1` and
        `teal-9` are both valid, and both resolve per theme.

    # ===========================================
    # Behaviour shared by every component
    # ===========================================
    NMAction:
      type: object
      description: |
        Something the client should do when the component is activated. An action
        names an intent; it never carries code. A client that does not understand
        an action ignores it rather than guessing, which is what lets a newer
        server talk to an older client without breaking it.
      required:
        - kind
      properties:
        kind:
          type: string
          description: The intent, such as navigate, play, mutate, dismiss or submit.
        target:
          type: string
          nullable: true
          description: What the intent applies to, usually a link or a component id.
        body:
          type: object
          additionalProperties: true
          nullable: true
        confirm:
          type: string
          nullable: true
          description: When set, the client confirms with this message before acting.

    NMAccessibility:
      type: object
      description: |
        The accessible name and role a payload can set. Every component ships a
        correct default, so this exists to override, not to supply what would
        otherwise be missing. A component that needs this field filled in to be
        accessible is a component with a bug.
      properties:
        label:
          type: string
          nullable: true
        described_by:
          type: string
          nullable: true
        role:
          type: string
          nullable: true
        live:
          type: string
          nullable: true
          enum: [off, polite, assertive]

    # ===========================================
    # Content a component draws rather than a way it looks
    # ===========================================
    NMTableCellKind:
      type: string
      description: |
        How a cell draws what its column points at. The design system builds the
        cell itself from this, which is why a table is described rather than
        assembled: a server that had to nest an avatar, a badge and a checkbox
        per row would restate the table's own anatomy on every screen.
      enum: [text, avatar-text, badge, rating, checkbox, actions]

    NMTableColumn:
      type: object
      description: |
        One column: what it is called, which field of a row it reads, and how
        that field draws.
      required:
        - label
        - key
        - type
      properties:
        label:
          type: string
          description: The header text. Empty for a column whose header is a control.
        key:
          type: string
          description: The row field this column reads.
        type:
          $ref: '#/components/schemas/NMTableCellKind'
        sortable:
          type: boolean
          nullable: true
          description: When true the header is a sort button carrying aria-sort.

    NMTableRow:
      type: object
      description: |
        One row, as the fields its columns read. Values are flat on purpose: a
        cell's appearance is the column's decision, so a row carries data and
        never markup.
      additionalProperties: true

    NMSelectOption:
      type: object
      description: |
        One choice in a select or a combobox: what a reader sees and what the
        form submits.
      required:
        - label
        - value
      properties:
        label:
          type: string
        value:
          type: string

    NMChatMessage:
      type: object
      description: |
        One message in a conversation. `variant` is who is speaking, which is
        what decides the side it sits on and the colour it takes.
      required:
        - variant
        - text
      properties:
        variant:
          type: string
          enum: [sent, received]
        text:
          type: string
        time:
          type: string
          nullable: true
        avatar:
          type: string
          nullable: true

    NMStep:
      type: object
      description: One step of a stepper, and what it says about itself.
      required:
        - label
      properties:
        label:
          type: string
        description:
          type: string
          nullable: true

    # ===========================================
    # The base every component's props extend
    # ===========================================
    NMComponentBase:
      type: object
      description: |
        What every component in this vocabulary carries, whatever it draws.

        `items` is here rather than on the container components alone, because a
        brick that cannot hold children is not a brick. A component that has no
        meaningful place to put children renders them after its own content.
      required:
        - id
      properties:
        id:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/DesignComponent'
          default: []
          description: Nested children, rendered inside this component.
        slots:
          type: object
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/DesignComponent'
          default: {}
          description: |
            Children for a slot the component names, keyed by that name. A card
            declares a header, a body and a footer; without this a payload could
            reach none of them, because every renderer filled the default slot
            and nothing else. Anything sent under a name the component does not
            declare is ignored rather than drawn somewhere it does not belong.
        box:
          $ref: '#/components/schemas/NMBox'
        surface:
          $ref: '#/components/schemas/NMSurface'
        color:
          type: string
          nullable: true
          description: |
            The palette family this component draws its accent from, such as
            `violet` or `red`. Any family the design system ships is accepted,
            not only the handful a given component enumerates: those are the
            designer's recommendation rather than the limit.

            Absent, the component follows the accent the app is set to, which is
            the behaviour a payload should want almost always. Naming one here
            is for the case where a single component has to stand apart from the
            rest of the interface.
        action:
          $ref: '#/components/schemas/NMAction'
        accessibility:
          $ref: '#/components/schemas/NMAccessibility'
        test_id:
          type: string
          nullable: true
          description: |
            A stable handle for tests. The box suites read the rendered geometry
            through this, which is why it is part of the contract rather than
            something each client invents.
        next_id:
          type: string
          nullable: true
          description: The component focus moves to next, for D-pad traversal.
        previous_id:
          type: string
          nullable: true
        context_menu_items:
          type: array
          items:
            $ref: '#/components/schemas/DesignContextMenuItem'
          default: []
        url:
          type: string
          nullable: true
          description: Where this component's data is fetched or refreshed from.
        properties:
          type: object
          additionalProperties: true
          nullable: true
          description: |
            Anything the contract has not named yet. This is the escape hatch that
            keeps an older client alive against a newer server, and it is not a
            place to put something that deserves a name.

    DesignContextMenuItem:
      type: object
      properties:
        id:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        icon:
          type: string
          nullable: true
        destructive:
          type: boolean
          default: false
        action:
          $ref: '#/components/schemas/NMAction'

    DesignComponent:
      type: object
      description: |
        The envelope, matching `Component` in `openapi-nm-components.yaml`. The
        `component` field discriminates, and `props` is that component's own
        schema, every one of which extends `NMComponentBase`.

        The concrete component schemas are generated from the design system into
        `openapi-nm-design-system.components.yaml` and are not hand-written here,
        because a contract maintained by hand alongside a generated one drifts.
      required:
        - id
        - component
        - props
      properties:
        id:
          type: string
        component:
          type: string
          description: Component type discriminator, such as NMButton or NMCard.
        props:
          type: object
          additionalProperties: true
          description: The component's props, extending NMComponentBase.
        update:
          $ref: '#/components/schemas/DesignUpdate'

    DesignUpdate:
      type: object
      description: When and from where this component refreshes itself.
      properties:
        when:
          type: string
          nullable: true
        link:
          type: string
          nullable: true
        body:
          type: object
          additionalProperties: true
          nullable: true